Security的运行流程
1、客户端发送一个登录请求
2、请求通过Security的过滤器链
3、Spring Boot 调用实现 UserDetailsService 接口的类获取后端保存的用户信息
4、将客户端发来的用户信息加密后 与 数据库保存的用户信息对比
5、若成功,则允许登录,然后响应消息经过过滤器链返回给客户端。
UserDetailsService 接口的实现
1、创建一个类,此类 实现 UserDetailsService接口
2、重写 loadUserByUsername 方法
此方法的作用:通过用户名加载用户,这个方法需要返回一个实现UserDetails接口的类,类里封装用户信息。
@Service
public class UserDetailsServiceImpl implements UserDetailsService{
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
/*
使用构造器从数据库内查找用户名为username的用户,并构造返回一个 UserDetailsImpl 类
此类即为实现了UserDetails接口的类
*/
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
User user = userMapper.selectOne(queryWrapper);
if(user == null) throw new RuntimeException("user is not exist!");
return new UserDetailsImpl(user);
}
}
UserDetails 接口类: 用于封装用户信息,包括用户名、密码、权限等。
// lombok 依赖,帮助写一些很无聊的方法
@Data
@AllArgsConstructor
@NoArgsConstructor
// 这个接口允许你自定义用户信息的存储和检索方式
public class UserDetailsImpl implements UserDetails {
// 封装的用户信息
User user;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.emptyList();
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
//判断账户信息是否有效
@Override
public boolean isAccountNonExpired() {
return true;
}
// 判断账户是否被锁定
@Override
public boolean isAccountNonLocked() {
return true;
}
// 判断身份信息是否有效
@Override
public boolean isCredentialsNonExpired() {
return true;
}
// 判断此用户是否启用
@Override
public boolean isEnabled() {
return true;
}
}
加密工具类
此加密工具被Security用来对用户密码进行加密,数据库内存储的用户密码是被这个加密工具类加密后的密码。 等客户端发来登录请求后,Security会用此加密工具对用户的登录密码加密,然后和数据库内的密码对比。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
// 数据库里面的密码也使用此类进行密码加密
return new BCryptPasswordEncoder();
}
}