配置自定义的用户存储
我们在 SecurityConfig 的配置类中 重写了 configure(AuthenticationManagerBuilder auth) 方法,我们可以通过 AuthenticationManagerBuilder 这个构造器类使用不同的用户存储,如 inMemoryAuthentication()基于内存的,jdbcAuthentication()基于关系型数据库的.
通过查看AuthenticationManagerBuilder的源码可以发现里面还有一个方法 userDetailsService(),允许我们自定义用户存储的实现.如下:
userDetailsService()方法 需要传入参数 “UserDetailsService”。而UserDetailsService是一个接口所以我们需要实现接口的loadUserByUsername(String s)方法。根据给定的用户名来查找用户。
loadUserByUsername()方法会返回代表给定用户的UserDetails对象 。而这个UserDetail 又是个什么呢?我们再次产看其源码,发现这也是一个接口,也就是说我们还要实现这个 UserDetail接口.这个结构
封装了用户的登陆信息
好了,了解了 userDetailsService 方法的构造,我们就可以着手写代码了。首先定义一个 MyUserService 实现 UserDetailsService 接口.并在重写的 loadUserByUsername 方法中返回 UserDetail类型的对象即可。
/** * @author cuiqq * @description: TODO * @date 2019-06-2115:36 */ public class MyUserService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //自定义用户存储数据来源,可以是从关系型数据库,非关系性数据库,或者其他地方获取用户数据。 User userEntity = new User("cuiqq", "123456"); //还可以在此设置账号的锁定,过期,凭据失效 等参数 //... // 设置 权限,可以是从数据库中查找出来的 ArrayList<GrantedAuthority> authorities = new ArrayList<>(); authorities.add(new SimpleGrantedAuthority("ROLE_USER")); authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); userEntity.setAuthorities(authorities); return userEntity; } }
@Data public class UserEntity implements UserDetails { /** * 用户名 */ private String username; /** * 密码 */ private String password; /** * 是否可用 */ private Boolean enabled; /** * 用户所拥有的权限 */ private List<? extends GrantedAuthority> authorities; /** * 用户的账号是否过期,过期的账号无法通过授权验证. true 账号未过期 */ private Boolean accountNonExpired = true; /** * 用户的账户是否被锁定,被锁定的账户无法通过授权验证. true 账号未锁定 */ private Boolean accountNonLocked = true; /** * 用户的凭据(pasword) 是否过期,过期的凭据不能通过验证. true 没有过期,false 已过期 */ private Boolean credentialsNonExpired = true; public UserEntity(String username, String password, Boolean enabled) { this.username = username; this.password = password; this.enabled = enabled; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @Override public String getPassword() { return password; } @Override public String getUsername() { return username; } @Override public boolean isAccountNonExpired() { return accountNonExpired; } @Override public boolean isAccountNonLocked() { return accountNonLocked; } @Override public boolean isCredentialsNonExpired() { return credentialsNonExpired; } @Override public boolean isEnabled() { return enabled; } }
除了我们自定义的UserEntity外,还有一个 User,其实这就是Spring Security为我们实现好的 UserDetails 类.我们可以看到它的源码如下:
public class User implements UserDetails, CredentialsContainer { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; // ~ Instance fields // ================================================================================================ private String password; private final String username; private final Set<GrantedAuthority> authorities; private final boolean accountNonExpired; private final boolean accountNonLocked; private final boolean credentialsNonExpired; private final boolean enabled; //... }
由于源码太长,这里只贴出一部分,可以看到这里面也有我们在UserEntity定义的字段.其实也不奇怪了,本来我们的 UserEntity 就是按着User进行改造的嘛.
之所以自定义UserEntity,这里是为了方面初学者进行快速入门,相比于User我们的UserEntity还是很简单的.
现在 我们的 UserDetailsService 已经完成了,接下来就是在 SecurityConfig 的configure方法中使用了,如下:
/** * 自定义用户存储 **/ @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(new MyUserService()); } }