SpringSecurity自定义用户认证逻辑
一.处理用户信息获取逻辑
用户信息获取逻辑是被封装到UserDetailsService接口中,loadUserByUsername方法作用是用户输入的username从存储去读取用户信息,然后封装到UserDetails这个实例中去,SpringSecurity会拿着这个用户信息进行处理,校验,如果校验通过了,就会把这个用户放到session中去,说明用户登录成功了,如果找不到,则会抛出UsernameNotFoundException用户名不存在这个异常,SpringSecurity捕获到这个异常也会显示对应的异常信息。
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
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.Component;
@Component
@Slf4j
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("登录用户名" + username);
//根据用户名查找用户信息,实际代码中用户名和密码是从数据库或第三方获取到的
return new User(username, "123456", AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
此时会出现java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id “null”,这是由于Spring security5中新增加了加密方式,并把原有的spring security的密码存储格式改了。我们只需要对用户注册或者修改时输入的密码进行某种方式加密,就可以了,而官方推荐的是使用bcrypt的加密方式。解决办法如具体修改见第三步
二.处理用户校验逻辑
UserDetails中的四个方法,通过四个方法的实现用来执行自己的校验逻辑
boolean isEnabled (); 账户是否失效(一般表示你这个用户是否被删了,逻辑删除)
boolean isAccountNonExpired (); 账户是否过期
boolean isCredentialsNonExpired (); 密码是否过期了
boolean isAccountNonLocked (); 用户帐号是否已被锁定(一般用于输入错误密码多次之后被锁定)
锁定用户一般可以恢复,密码过期之后一般会提醒用户重新设置密码 删除用户是不能恢复的
此时返回值需要使用该构造器进行返回
return new User(username, new BCryptPasswordEncoder().encode("123456"),true,true,true,true,
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
只要有一个方法的返回值为false,则校验不通过(实际项目中,这四个参数也同用户名和密码一样,需存入数据库中)。
三.处理密码加密解密
1. 在config中添加bean
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
2. 在service中注入,并对密码进行加密 passwordEncoder.encode(“123456”)
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("登录用户名" + username);
//根据用户名查找用户信息
return new User(username, passwordEncoder.encode("123456"),
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
注意,在这里,返回的密码在实际业务中应该是在用户注册或者修改时存入数据库之前进行加密,而不是在这里进行加密。
3. PasswordEncoder接口中,有两个方法
String encode(CharSequence rawPassword)
encode方法对密码进行加密,是供自己来调用的,是在将用户信息插入到数据库之前进行调用加密操作的。
boolean matches(CharSequence rawPassword, String encodedPassword);
matches方法是用来判断登录请求中加密后的代码和UserDetails中返回的密码是否匹配,是由springsecurity来调用的。