目录
一、概述
二、UserDetailsService详解
三、PasswordEncoder 密码解析器详解
Spring Security 学习专栏
1. Spring Security 入门学习(一)
2. Spring Security 自定义认证管理器和讲解 (二)
3. Spring Security 接口详解 (三)
4. Spring Security 工作原理 (四)
通过前面几篇文章大概了解和学习Spring Security,看原理相关文章确实比较枯燥(也可以先学习后面的章节,在学习这篇文章),但是对学习Spring Security会了解更加透彻。
当什么也没有配置的时候,账号和密码是由 Spring Security 定义生成的。而在实际项目中账号和密码都是从数据库中查询出来的。所以我们要通过自定义逻辑控制认证逻辑。如果需要自定义逻辑时,只需要实现 UserDetailsService 接口即可。接口定义如下:
public interface UserDetailsService {
/**
* Locates the user based on the username. In the actual implementation, the search
* may possibly be case sensitive, or case insensitive depending on how the
* implementation instance is configured. In this case, the UserDetails
* object that comes back may have a username that is of a different case than what
* was actually requested..
*
* @param username the username identifying the user whose data is required.
*
* @return a fully populated user record (never null
)
*
* @throws UsernameNotFoundException if the user could not be found or the user has no
* GrantedAuthority
*/
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
返回值 UserDetails 是一个接口,定义如下
public interface UserDetails extends Serializable {
/**
* 获取所有权限
*
*/
Collection extends GrantedAuthority> getAuthorities();
/**
* 密码
*
*/
String getPassword();
/**
* 用户名
*
*/
String getUsername();
/**
* 账号是否过期
*
*/
boolean isAccountNonExpired();
/**
* 账号是否被锁
*
*/
boolean isAccountNonLocked();
/**
* 凭证(密码) 是否过期
*/
boolean isCredentialsNonExpired();
/**
* 是否可用
*/
boolean isEnabled();
}
的实例就只能返回接口的实现类。SpringSecurity 中提供了如下的实例。对于我们只需要使用里面的 User 类即可。注意 User 的全限定路径是:
org.springframework.security.core.userdetails.User 此处经常和系统中自己开发的 User 类弄混。
其中构造方法有两个,调用其中任何一个都可以实例化
UserDetails 实现类 User 类的实例。而三个参数的构造方法实际上也是调用 7 个参数的构造方法。
/**
* Calls the more complex constructor with all boolean arguments set to {@code true}.
*/
public User(String username, String password,
Collection extends GrantedAuthority> authorities) {
this(username, password, true, true, true, true, authorities);
}
此处的用户名应该是客户端传递过来的用户名。而密码应该是从数据库中查询出来的密码。SpringSecurity 会根据 User 中的 password 和客户端传递过来的 password 进行比较。如果相同则表示认证通过,如果不相同表示认证失败。
UserDetails 里面的权限对于后面学习授权是很有必要的,包含的所有内容为此用户具有的权限,如有里面没有包含某个权限,而在做某个事情时必须包含某个权限则会出现 403。通常都是通过AuthorityUtils.commaSeparatedStringToAuthorityList(“”) 来创建 authorities 集合对象的。参数是一个字符串,多个权限使用逗号分隔。
方法参数
方法参数表示用户名。此值是客户端表单传递过来的数据。默认情况下必须叫 username ,否则无法接收。
异常
UsernameNotFoundException 用户名没有发现异常。在 loadUserByUsername 中是需要通过自己的
逻辑从数据库中取值的。如果通过用户名没有查询到对应的数据,应该抛出UsernameNotFoundException ,系统就知道用户名没有查询到。
Spring Security 要求容器中必须有 PasswordEncoder 实例。所以当自定义登录逻辑时要求必须给容器注入 PaswordEncoder 的bean对象。
接口介绍
public interface PasswordEncoder {
String encode(CharSequence rawPassword);
boolean matches(CharSequence rawPassword, String encodedPassword);
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
内置解析器介绍
在 Spring Security 中内置了很多解析器。
BCryptPasswordEncoder 简介
BCryptPasswordEncoder 是 Spring Security 官方推荐的密码解析器,平时多使用这个解析器。
BCryptPasswordEncoder 是对 bcrypt 强散列方法的具体实现。是基于Hash算法实现的单向加密。
可以通过strength控制加密强度,默认 10.
@Slf4j(topic = "BCryptPasswordTest")
public class BCryptPasswordTest {
public static void main(String[] args) {
//创建解析器
PasswordEncoder pw = new BCryptPasswordEncoder();
//对密码加密
String encode = pw.encode("123");
log.info("encode:{}",encode);
//判断原字符和加密后内容是否匹配
boolean matches = pw.matches("1234", encode);
log.info("=====>matches:{}", matches);
}
}