SpringSecurity(一、二、三)身份认证的用户名和密码是启动服务器自动生成的,或者是代码中写死的,存储在内存中。而实际项目中应该从动态的从数据库中获取进行身份认证。
 
1.实现流程:  
  (1)关注 UserDetailsService 、 UserDetails 接口
  (2)自定义一个 UserDetailsService 接口的实现类 CustomUserDetailsService ,实现该接口中的loadUserByUsername 方法 ,通过该方法定义获取用户信息的逻辑。
  (3)从数据库获取到的用户信息封装到 UserDetail 接口的实现类中(Spring Security 提供了一个org.springframework.security.core.userdetails.User 实现类封装用户信息)。
  (4)如果未获取到用户信息,则抛出异常 throws UsernameNotFoundException
public interface UserDetails extends Serializable { 
  //此用户可访问的资源权限
  Collection<? extends GrantedAuthority> getAuthorities();
  //用户名
  String getPassword();
  //密码
  String getUsername();
  //帐户是否过期(true 未过期,false 已过期)   boolean isAccountNonExpired();
  //帐户是否被锁定(true 未锁定,false 已锁定),锁定的用户是可以恢复的   boolean isAccountNonLocked();
  //密码是否过期(安全级别比较高的系统,如30天要求更改密码,true 未过期,false 过期)   boolean isCredentialsNonExpired();
  //帐户是否可用(一般指定是否删除,系统一般不会真正的删除用户信息,而是假删除,通过一个状态码标志 用户被删除)删除的用户是可以恢复的   
boolean isEnabled();
}

2.自定义CustomUserDetailsService类实现UserDetailsService接口

/**
 * 查询数据库中的用户信息
 */
@Component("CustomUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
   Logger logger=LoggerFactory.getLogger(CustomUserDetailsService.class);

   @Autowired
    BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
       logger.info("请求认证的用户名:"+username);

       //1.通过请求的用户名去数据库中查询用户信息
        if (!"zcc".equals(username)){
            throw new UsernameNotFoundException("用户名或密码错误");
        }

        //假设当前这个用户在数据库中存储的密码是123
        String password=bCryptPasswordEncoder.encode("123");

        //2.查询该用户所拥有的权限
        

        // 3.封装用户信息: username用户名,password数据库中的密码,authorities资源权限标识符
        // SpringSecurity 底层会校验是否身份合法。
        return  new User(username,password, AuthorityUtils.commaSeparatedStringToAuthorityList("ADMIN"));

    }
}

3.重构安全配置类SpringSecurityConfig

  注入 CustomUserDetailsService  在confifigure(AuthenticationManagerBuilder auth) 方法中指定认证方式
   @Autowired
    CustomUserDetailsService customUserDetailsService;


    /**
     * 认证管理器:
     * 1、认证信息提供方式(用户名、密码、当前用户的资源权限)
     * 2、可采用内存存储方式,也可能采用数据库方式等
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //基于内存存储认证信息 存储的密码必须是加密后的 不然会报错:There is no PasswordEncoder mapped for the id "null"
        //auth.inMemoryAuthentication().withUser("zcc").password("123").authorities("ADMIN");
        /*String password = bCryptPasswordEncoder().encode("123");
        logger.info("加密后的密码:" + password);
        auth.inMemoryAuthentication().withUser("zcc").password(password).authorities("ADMIN");*/


        // 指定使用自定义查询用户信息来完成身份认证
        auth.userDetailsService(customUserDetailsService);

    }

 完整代码地址:https://gitee.com/zhechaochao/security-parent.git

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2021-01-05 00:03  西门夜说  阅读(2427)  评论(1编辑  收藏  举报