四、Spring Boot集成Spring Security之认证流程
二、概要说明
- 本文主要介绍登录登出业务流程,所以使用基于内存的用户名密码,暂不介绍授权相关内容,后续会详细介绍基于数据库的认证及授权
- 如何查看基于内存的默认用户名密码
- 如何配置基于内存的自定义用户名密码
- 本文与上文有强关联性,如果对过滤器链中登录相关的过滤器不熟悉的同学,请先查看三、Spring Boot集成Spring Security之securityFilterChain过滤器链详解
三、基于内存的用户名密码
1、默认用户名密码
- 一、Spring Boot集成Spring Security之自动装配中第六节已介绍当用户未自定义认证接口时,生成默认认证接口inMemoryUserDetailsManager,其中用户名为user,密码为随机生成的uuid,项目启动时会打印在控制台中

- 用户名密码源码

2、自定义用户名密码
- 上一小节【用户名密码源码】中配置绑定可以配置自定义用户名、密码
- 通过配置文件配置用户名密码

3、为方便测试添加测试接口TestController
package com.yu.demo.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
public class TestController {
@GetMapping("/hello")
public String hello() {
return "success";
}
}

四、登录登出重要概念介绍
- 安全上下文仓库(SecurityContextRepository):用于存储安全上下文,默认基于session实现(HttpSessionSecurityContextRepository)
- 安全上下文持有者(SecurityContextHolder):用于存储本次请求的安全上下文,默认基于ThreadLocal实现
- 安全上下文(SecurityContext):用于存储认证信息
- 认证信息(Authentication):用于存储用户及认证结果信息,主要实现类有
- 用户名密码认证Token:UsernamePasswordAuthenticationToken
- 匿名认证Token:AnonymousAuthenticationToken
- 登录页面请求:跳转到登录页面的请求
- 登录请求:在登录页面输入用户名密码后提交的请求
- 登出页面请求:跳转到登出页面的请求
- 登出请求:在登出页面确认登出提交的请求
五、登录业务逻辑
1、登录业务相关过滤器
- SecurityContextPersistenceFilter
- UsernamePasswordAuthenticationFilter
- DefaultLoginPageGeneratingFilter
- AnonymousAuthenticationFilter
- ExceptionTranslationFilter
- FilterSecurityInterceptor
2、访问业务请求处理流程
1)、访问业务请求地址被拦截,重定向到登录页面请求
浏览器访问业务请求地址:http://localhost:8080/test/hello
SecurityContextPersistenceFilter处理请求:
- 从安全上下文仓库中获取安全上下文为空,创建没有认证信息的安全上下文(SecurityContextImpl)
- 将第1步中获取的安全上下文设置到安全上下文持有者中
- 执行后续过滤器链
- 源码

AnonymousAuthenticationFilter处理请求:
- 获取安全上下文持有者中的安全上下文中的认证信息为空
- 创建匿名认证信息
- 创建新的没有认证信息的安全上下文
- 将第2步中的匿名认证信息设置到第3步中的安全上下文中
- 将第3步中的安全上下文中设置到安全上下文持有者中
- 执行后续过滤器链
- 源码

FilterSecurityInterceptor处理请求:
- 验证安全上下文持有者中的安全上下文中的匿名认证信息通过
- 验证授权信息失败(业务请求地址未设置可以匿名访问时),抛出AccessDeniedException异常
- 源码

ExceptionTranslationFilter处理请求:
- 捕获FilterSecurityInterceptor抛出的AccessDeniedException异常
- 判断是因为匿名访问导致的授权异常
- 创建新的没有认证信息的安全上下文
- 将第3步中的安全上下文中设置到安全上下文持有者中
- 重定向到登录页面:http://localhost:8080/login
- 源码

SecurityContextPersistenceFilter处理请求:
- 执行chain.doFilter之后的代码
- 获取安全上下文持有者中的安全上下文
- 删除安全上下文持有者中的安全上下文
- 将第2步中获取的安全上下文保存到安全上下文仓库中
- 源码

重定向登录页面请求:http://localhost:8080/login(GET)
2)、重定向定页面请求,返回登录页面
SecurityContextPersistenceFilter处理请求:
- 从安全上下文仓库中获取安全上下文为空,创建没有认证信息的安全上下文(SecurityContextImpl)
- 将第1步中获取的安全上下文设置到安全上下文持有者中
- 执行后续过滤器链
- 源码(同上)
DefaultLoginPageGeneratingFilter处理请求:
- 判断是跳转到登录页面的请求
- 生成默认登录页面
- 返回并渲染生成的默认登录页面
- 源码

SecurityContextPersistenceFilter处理请求:
- 执行chain.doFilter之后的代码
- 获取安全上下文持有者中的安全上下文
- 删除安全上下文持有者中的安全上下文
- 将第2步中获取的安全上下文保存到安全上下文仓库中
- 源码(同上)
3)、输入正确用户名密码,重定向到业务请求
SecurityContextPersistenceFilter处理请求:
- 从安全上下文仓库中获取安全上下文为空,创建没有认证信息的安全上下文(SecurityContextImpl)
- 将第1步中获取的安全上下文设置到安全上下文持有者中
- 执行后续过滤器链
- 源码(同上)
UsernamePasswordAuthenticationFilter处理请求:
- 判断需要认证(AbstractAuthenticationProcessingFilter.doFilter方法)
- 认证用户名密码成功,生成已认证的认证信息UsernamePasswordAuthenticationToken
- 创建新的没有认证信息的安全上下文
- 将第2步中的认证信息设置到第3步中的安全上下文中
- 将第3步中的安全上下文设置到安全上下文持有者中
- 将第3步中的安全上下文保存到局部变量安全上下文仓库中(空实现)
- 重定向到业务请求地址:http://localhost:8080/test/hello
- 源码

SecurityContextPersistenceFilter处理请求:
- 执行chain.doFilter之后的代码
- 获取安全上下文持有者中的安全上下文
- 删除安全上下文持有者中的安全上下文
- 将第2步中获取的安全上下文保存到安全上下文仓库中
- 源码(同上)
4)、重定向到业务请求
SecurityContextPersistenceFilter处理请求:
- 从安全上下文仓库中获取已认证的安全上下文
- 将第1步中获取的安全上下文设置到安全上下文持有者中
- 执行后续过滤器链
- 源码(同上)
FilterSecurityInterceptor处理请求:
- 验证安全上下文持有者中的安全上下文中的认证信息通过
- 验证授权成功
- 调用接口返回数据
- 源码

SecurityContextPersistenceFilter处理请求:
- 执行chain.doFilter之后的代码
- 获取安全上下文持有者中的安全上下文
- 删除安全上下文持有者中的安全上下文
- 将第2步中获取的安全上下文保存到安全上下文仓库中
- 源码(同上)
六、登出业务实现逻辑
1、登出业务相关过滤器
- SecurityContextPersistenceFilter
- LogoutFilter
- DefaultLogoutPageGeneratingFilter
2、访问登出页面请求处理流程
浏览器访问登出请求地址:http://localhost:8080/logout
SecurityContextPersistenceFilter处理请求:
- 从安全上下文仓库中获取已认证的安全上下文
- 将第1步中获取的安全上下文设置到安全上下文持有者中
- 执行后续过滤器链
- 源码(同上)
DefaultLogoutPageGeneratingFilter处理请求:
- 判断是跳转到登出页面的请求
- 生成默认登出页面
- 返回并渲染生成的默认登出页面
- 源码

SecurityContextPersistenceFilter处理请求:
- 执行chain.doFilter之后的代码
- 获取安全上下文持有者中的安全上下文
- 删除安全上下文持有者中的安全上下文
- 将第2步中获取的安全上下文保存到安全上下文仓库中
- 源码(同上)
3、登出页面确认登出请求处理流程
1)、确认登出,重定向到登录页面请求
SecurityContextPersistenceFilter处理请求:
- 从安全上下文仓库中获取已认证的安全上下文
- 将第1步中获取的安全上下文设置到安全上下文持有者中
- 执行后续过滤器链
- 源码(同上)
LogoutFilter处理请求:
- 判断是登出请求
- 获取安全上下文持有者中的安全上下文
- 登出处理器处理登出业务
- 删除安全上下文持有者中的安全上下文
- 创建没有认证信息的安全上下文
- 将第2步中的安全上下文保存到安全上下文仓库中
- 重定向到登录页面
- 源码

SecurityContextPersistenceFilter处理请求:
- 执行chain.doFilter之后的代码
- 获取安全上下文持有者中的安全上下文
- 删除安全上下文持有者中的安全上下文
- 将第2步中获取的安全上下文保存到安全上下文仓库中
- 源码(同上)
2)、登录页面请求
第五节登录业务逻辑已介绍,不再赘述。
七、说明
- Spring Boot集成Spring Security默认是非前后分离架构
- 本文介绍的流程是非前后分离版本的处理流程
- 前后分离处理流程较为简单
- 未认证时访问业务接口,返回未认证错误信息
- 调用登录接口成功后返回Token,此后请求头中携带此Token
- 调用登出接口成功后返回成功,后端将该Token失效
- 携带Token访问业务接口,后端验证Token成功后,调用业务接口并返回数据
四、Spring Boot集成Spring Security之认证流程的更多相关文章
- Spring Boot集成Spring Data Reids和Spring Session实现Session共享
首先,需要先集成Redis的支持,参考:http://www.cnblogs.com/EasonJim/p/7805665.html Spring Boot集成Spring Data Redis+Sp ...
- SpringBoot系列:Spring Boot集成Spring Cache,使用EhCache
前面的章节,讲解了Spring Boot集成Spring Cache,Spring Cache已经完成了多种Cache的实现,包括EhCache.RedisCache.ConcurrentMapCac ...
- SpringBoot系列:Spring Boot集成Spring Cache,使用RedisCache
前面的章节,讲解了Spring Boot集成Spring Cache,Spring Cache已经完成了多种Cache的实现,包括EhCache.RedisCache.ConcurrentMapCac ...
- Spring Boot 集成 Spring Security 实现权限认证模块
作者:王帅@CodeSheep 写在前面 关于 Spring Security Web系统的认证和权限模块也算是一个系统的基础设施了,几乎任何的互联网服务都会涉及到这方面的要求.在Java EE领 ...
- Spring boot 集成Spring Security
依赖jar <dependency> <groupId>org.springframework.cloud</groupId> <artifactId> ...
- Spring Boot 集成spring security4
项目GitHub地址 : https://github.com/FrameReserve/TrainingBoot Spring Boot (三)集成spring security,标记地址: htt ...
- Spring boot集成spring session实现session共享
最近使用spring boot开发一个系统,nginx做负载均衡分发请求到多个tomcat,此时访问页面会把请求分发到不同的服务器,session是存在服务器端,如果首次访问被分发到A服务器,那么se ...
- Spring Boot 集成 Spring Security
1.添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId> ...
- Spring Boot 集成 Spring Security 入门案例教程
前言 本文作为入门级的DEMO,完全按照官网实例演示: 项目目录结构 Maven 依赖 <parent> <groupId>org.springframework.boot&l ...
- Spring Boot 集成 Spring Security 使用自定义的安全数据源
编写一个类自定义实现 UserDetailsService 接口 @Service("customUserDetailService") public class CustomUs ...
随机推荐
- 【Java-GUI】11 Swing06 JTable
静态数据表格的样子: package cn.dzz; import javax.swing.*; import java.awt.*; public class JTable { JFrame jFr ...
- 多节点高性能计算GPU集群的构建
建议参考原文: https://www.volcengine.com/docs/6535/78310 ============================================= 一直都 ...
- 面向分布式强化学习的经验回放框架——Reverb: A Framework for Experience Replay
论文题目: Reverb: A Framework for Experience Replay 地址: https://arxiv.org/pdf/2102.04736.pdf 框架代码地址: htt ...
- NVIDIA显卡的利用率“Volatile GPU Util"是什么???
相关: CPU端多进程/多线程调用CUDA是否可以加速??? 如何实现nvidia显卡的cuda的多kernel并发执行??? ==================================== ...
- MD5签名生成,字典排序,实际生产
1.背景 作用:防止请求参数篡改,限制请求时效性: 常用方式:md5签名 关键:签名Key 常用签名原串排列:字母顺序.key1=value1&key2=value2....key (注意:签 ...
- 【技术积累】如何处理Feign的超时问题
在使用Feign进行微服务之间的通信时,由于网络延迟等原因,可能会出现请求超时的情况.为了解决这个问题,我们可以对Feign进行配置,设置超时时间. 配置Feign的超时时间 在使用Feign时,我们 ...
- 海豚调度任务类型Apache SeaTunnel部署指南
Apache DolphinScheduler已支持Apache SeaTunnel任务类型,本文介绍了SeaTunnel任务类型如何创建,任务参数,以及任务样例. 一.Apache SeaTunne ...
- Git-HEAD 的含义
在 Git 中,"HEAD" 是一个特殊的引用,它指向当前所处的分支或提交. 当你进行一些操作时,比如提交代码.切换分支等,HEAD 的指向会随之改变.下面是 HEAD 在不同情况 ...
- 面试必问之redis
这里是我作为10年面试经验总结的面试中必问问题 问题一 简单介绍下redis redis是当前比较热门的NOSQL系统之一,它是一个开源的使用ANSI c语言编写的key-value存储系统(区别于M ...
- C++17新特性
C++17新特性 语言特性 使用auto声明非类型模板参量 折叠表达式 提供模板参数包的折叠 template <typename... Args> bool logicalAnd(Arg ...