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