上一篇进行了最简单的Spring Security的初始搭建,像用户名和密码都是固定的,这篇就来讲讲自定义用户认证逻辑的实现,包括用户信息的获取,用户密码的校验以及用户密码的加密校验。
处理用户信息获取逻辑
源码
- 用户信息的获取逻辑被封装在UserDetailsService接口中,接口源码:
public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
- 作用:
根据用户前端输入的用户名,会到存储去读取用户信息封装到返回值UserDetails中
,如果通过输入的用户名没法找到数据库中数据,则会抛出一个UsernameNotFoundException异常。
实操
- 我们可以创建自己的一个MyUserDetailsService,实现上面的接口,在loadUserByUsername方法中进行一个数据库用户信息的查询返回。
@Component
public class MyUserDetailsService implements UserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(MyUserDetailsService.class);
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LOGGER.info("登录名:" + username);
// balabala,根据用户名查找用户密码等信息返回(记得实际开发中是查库得到的),第三个参数是用户授权,后面再来详细讲
return new User(username, "123456", AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
- 效果:任意用户名,密码是
123456
才能进行登录(假装上面的密码是数据库中查到的!)
处理用户校验逻辑
源码
- UserDetails接口解析,该接口用于返回用户信息。
public interface UserDetails extends Serializable {
/**
* 用户授权
*/
Collection<? extends GrantedAuthority> getAuthorities();
/**
* 用户密码
*/
String getPassword();
/**
* 用户名
*/
String getUsername();
/**
* 以下四个方法可以自定义校验逻辑,返回账户是否过期,true表示没有过期
*/
boolean isAccountNonExpired();
/**
* 账户是否被锁定或者冻结(一般可恢复),true表示没被冻结
*/
boolean isAccountNonLocked();
/**
* 密码是否过期,true表示没有过期,可能有的网站需求密码需要30天更换等
*/
boolean isCredentialsNonExpired();
/**
* 账户是否可用或者是否被删(一般不可恢复),true表示可用
*/
boolean isEnabled();
}
实操
- 演示:以上四个boolean类型的方法只要有一个不为true都不能够通过登录校验
@Component
public class MyUserDetailsService implements UserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(MyUserDetailsService.class);
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LOGGER.info("登录名:" + username);
// balabala,根据用户名查找用户密码等信息返回,第三个参数是用户授权,后面再来详细讲
return new User(username, "123456",
true, true, true, false,
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
处理密码加密解码
源码
- PasswordEncoder接口解析,该接口用于密码的加密解密
public interface PasswordEncoder {
/**
* 密码加密,在注册的时候,密码插入数据库之前需要你手动调用进行一个加密操作
*/
String encode(CharSequence var1);
/**
* 判断加密的密码和用户传过来的密码是否匹配,该方法由security调用,匹配上了返回true,否则返回false
*/
boolean matches(CharSequence var1, String var2);
}
实操
- 配置上面接口的一个实例Bean。
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
- 记得我们的密码是被加密的,所以数据库中的密码应该是被加密过的。
public class MyUserDetailsService implements UserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(MyUserDetailsService.class);
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LOGGER.info("登录名:" + username);
// balabala,根据用户名查找用户密码等信息返回,第三个参数是用户授权,后面再来详细讲
String password = passwordEncoder.encode("123456");
return new User(username, password,
true, true, true, false,
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
- 演示,结果就是输入正确密码才能登陆,这里我们发现对同一个密码加密后的密文是不一样的,这是BCryptPasswordEncoder提供的加密方式,当然你可以自己实现加密,比如MD5加密方式等。