文章目录
往期回顾:Spring Boot集成Spring Security专栏及各章节快捷入口
- Spring Boot集成Spring Security专栏
- 一、Spring Boot集成Spring Security之自动装配
- 二、Spring Boot集成Spring Security之实现原理
- 三、Spring Boot集成Spring Security之过滤器链详解
- 四、Spring Boot集成Spring Security之认证流程
- 五、Spring Boot集成Spring Security之认证流程2
- 六、Spring Boot集成Spring Security之前后分离认证流程最佳方案
- 七、Spring Boot集成Spring Security之前后分离认证最佳实现
- 八、Spring Boot集成Spring Security之前后分离认证最佳实现对接测试
前言
本文介绍Spring Security基于数据的认证过程,配合以下内容观看效果更佳!!!
- Spring Security与Spring Boot集成时,Spring Security的装配过程及每个组件的作用,请查看一、Spring Boot集成Spring Security之自动装配
- Spring Security实现原理是什么样的,委托过滤器代理,过滤器链代理,过滤器链是如何加载和工作的,请查看二、Spring Boot集成Spring Security之实现原理
- Spring Security默认过滤器链有哪些过滤器,这些过滤器是如何实现认证的,实现认证的每个过滤器有什么作用及如何工作的,请查看三、Spring Boot集成Spring Security之过滤器链详解
- Spring Security默认配置时的认证过程,登录、登出的详细过程是怎么样的,请查看四、Spring Boot集成Spring Security之认证流程
- Spring Security认证过程是怎样的,如何基于数据库实现认证,请查看五、Spring Boot集成Spring Security之认证流程2
一、概要说明
- 上文已详细介绍了四、Spring Boot集成Spring Security之认证流程
- 本文则着重介绍用户名密码认证过滤器UsernamePasswordAuthenticationFilter的实现原理过程
- 认证管理器(authenticationManager)
- 认证提供者(AuthenticationProvider)
- 自定义配置用户名密码实现(UserDetailsService)
二、UsernamePasswordAuthenticationFilter
1、结构及作用
- 继承AbstractAuthenticationProcessingFilter
- 初始化请求地址
- 初始化authenticationManager
- 初始化successHandler
- 初始化failureHandler
- 实现过滤器入口doFilter方法
- doFilter方法调用抽象方法attemptAuthentication,attemptAuthentication供子类实现完成用户名密码验证业务
- 认证成功时更新安全上下文,并调用successHandler.onAuthenticationSuccess
- 认证失败时删除安全上下文,并调用failureHandler.onAuthenticationFailure
- 实现attemptAuthentication方法
- 从请求中获取用户名密码
- 生成未认证的Authentication
- 调用authenticationManager的authenticate方法完成用户名密码验证
三、认证管理器(AuthenticationManager)
1、作用
- 完成Authentication的认证
2、ProviderManager(默认实现)
- ProviderManager实现AuthenticationManager接口
- AuthenticationManager的作用的是完成Authentication的认证
- 但是ProviderManager并未直接完成Authentication的认证
- 而是提供一个AuthenticationProvider集合
- 遍历AuthenticationProvider集合来完成Authentication的认证
- 当需要多种认证方式时,可以注册自定义的AuthenticationProvider,后续介绍注册方式
四、AuthenticationProvider
1、作用
- 调用接口获取用户信息UserDetails
- 验证用户及密码是否可用
2、DaoAuthenticationProvider(默认实现)
- DaoAuthenticationProvider继承AbstractUserDetailsAuthenticationProvider实现AuthenticationProvider接口
- 调用retrieveUser方法获取用户信息UserDetails
- 调用userDetailsService.loadUserByUsername获取用户信息UserDetails
- 验证用户是否存在并可用,不存在或者不可用时抛异常(过期、锁定、启用)
- 验证密码是否可用,不可用时抛异常(为空、过期)
- 使用密码加密器校验密码(界面输入的密码和数据库已加密的密码)
- 密码不一致时抛异常
五、UserDetailsService
1、作用
- 通过用户名username获取用户信息UserDetails
- 返回用户信息UserDetails
2、InMemoryUserDetailsManager(默认实现)
- 项目启动时会默认生成一个用户名密码,存在内存中
- 通过用户名获取该用户并返回
3、推荐实现:自定义UserDetailsService
- 通过用户名从数据库中获取到用户
- 数据库用户转为UserDetails,数据库中未设置的属性像是否启用、账号未过期、密码未过期、账号未锁定直接设置为true即可
package com.yu.demo.service.impl;
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.Service;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
//@Autowired
//private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//TODO 通过username从数据库中获取用户,将用户转UserDetails
//User user = userService.getByUsername(username);
//return new User(username, user.getPassword(), user.getEnable(), user.getAccountNonExpired(), user.getCredentialsNonExpired(), user.getAccountNonLocked(), user.getAuthorities());
//{noop}不使用密码加密器,密码123的都可以验证成功
return new User(username, "{noop}123", true, true, true, true, AuthorityUtils.NO_AUTHORITIES);
}
}