原创文章转载请注明来源:https://blog.csdn.net/weixin_41756573/article/details/89060081

初次接触spring security,写的不好,也许还会有效bug,请多指教,欢迎留言。持续更新中

项目的目录结构

springboot2.0.1整合spring security

1.完整的pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.system.security</groupId>
    <artifactId>springboot-springsecurity</artifactId>
    <version>0.0.1-SNAPSHOT</version>


    <!-- 父依赖 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <dependencies>
        <!-- spring boot web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- spring boot security -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
            <scope>runtime</scope>
        </dependency>

        <!-- mysql jdbc 驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

        <!-- druid 数据源 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.6</version>
        </dependency>

        <!-- 模板引擎 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- -->
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity4</artifactId>
        </dependency>

    </dependencies>

</project>

2.启动类

package com.system.security;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.system.security.mapper") // 整合mybatis
public class SpringbootSecurity {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootSecurity.class, args);
    }

}
3.class WebSecurityConfiguration extends WebSecurityConfigurerAdapter(重点)

作用:是对spring security的整体配置,主要是关于登录验证资源访问的配置

package com.system.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/***
 * spring security 安全配置中心
 * @author BAIAYANG
 * @Time 2019.4.1
 */
@Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
    
    /**
     * 配置密码的加密与解密
     * @return 返回加密的方式(比如MD5,BCryptPasswordEncoder:security自带的加密方式等)
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    /**
     * 对spring security 的配置
     * 拦截url
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin() //使用表单登录
            .loginPage("/login.html") // 指向登录页面,或者是路由(注意/)
            .loginProcessingUrl("/user_login") // 通知UsernamePasswordAuthenticationFilter该路径是处理登录请求的路径
            .and()
            .authorizeRequests() //授权操作
            .antMatchers("/login.html").permitAll() // permitAll 任何身份均可以访问
            .antMatchers("/user_info").hasRole("ADMIN")  // hasRole 只有拥有该角色的人才可以访问;.antMatchers(HttpMethod.GET,"/user_info/*"),第一个参数指定方法的请求方式,通配路径
            .anyRequest()  // 任何请求
            .authenticated() // 需要身份认证
            .and()
            .csrf().disable(); // 关闭跨站请求防护
    }
    
    /**
     * 取消对静态资源的拦截
     */
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/js/**","/css/**","/images/**");//对于这些静态文件,忽略拦截
    }
    
}

重点一:搭建用户登录验证的功能

1.spring security 的 UserDetails

2.spring security 的 UserDetailsService

3.spring security 的 PasswordEncode

我对UserDetails的理解

作用:封装登录的用户信息,为用户是否可以登录做准备

package com.system.security.entity;

import java.util.Collection;
import java.util.List;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;

public class MyUserDetails extends User implements UserDetails {

    private static final long serialVersionUID = -5851249649932993238L;
    
    /**
     * 该用户所有角色的集合
     */
    private List<Role> roles;
    
    /**
     * 通过构造函数将User对象注入以及该用户的所有角色
     */
    public MyUserDetails(User user,List<Role> roles) {
        super(user);
        this.roles = roles;
    }

    /**
     * 获取用户的角色信息
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if(roles==null || roles.size()<1) {
            return AuthorityUtils.commaSeparatedStringToAuthorityList("");
        }
        StringBuilder commaBuilder = new StringBuilder();
        for(Role role : roles){
            commaBuilder.append("ROLE_"+role.getName()).append(",");
        }
        String authorities = commaBuilder.substring(0,commaBuilder.length()-1);
        return AuthorityUtils.commaSeparatedStringToAuthorityList(authorities);
    }

    /**
     * 账号是否过期
     */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * 指定用户是否被锁定
     */
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    /**
     * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    /**
     * 是否被禁用,禁用的用户不能身份验证
     */
    @Override
    public boolean isEnabled() {
        return true;
    }

}

我对UserDetailsService的理解

作用:查询用户以及角色信息,将信息封装为UserDetails传递给spring security,做出判断

package com.system.security.service.impl;

import java.util.List;
import javax.annotation.Resource;

import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import com.system.security.entity.MyUserDetails;
import com.system.security.entity.Role;
import com.system.security.entity.User;
import com.system.security.mapper.RoleUserMapper;
import com.system.security.mapper.UserMapper;

/***
 * 处理用户登录的请求
 * @author BAIYANG
 *
 */
@Service
public class MyUserDetailsService implements UserDetailsService {
    
    @Resource
    private UserMapper userMapper;
    
    @Resource
    private RoleUserMapper roleUserMapper;

    /**
     * 通过用户名获取一个UserDetails对象
     * 和你在filter配置的做比较
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //1.根据用户名查询用户信息
        User user = userMapper.findByUserName(username);
        if(user==null) {
            throw new UsernameNotFoundException(username);
        }else{
        //2.查询该用户的角色信息
        List<Role> roles = roleUserMapper.findRolesByUserId(user.getId());
        
        //3.将用户信息封装为一个UserDetails
        return new MyUserDetails(user, roles);
        
        // 模拟,注意密码的解密new BCryptPasswordEncoder().encode()注册时完成的加密,实际开发中直接将密码封装到这里即可
        //return new User(username, new BCryptPasswordEncoder().encode("123456"), //AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
        /**
         * org.springframework.security.core.userdetails.User.User(String username, String password, Collection<? extends GrantedAuthority> authorities)
         * username 用户名
         * password 密码
         * authorities 权限的集合
         */
        }
    }

}
 

 

相关文章: