基于Spring Security 6的OAuth2 系列之八 - 授权服务器--Spring Authrization Server的基本原理
之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级为6.3.0。无论是Spring Security的风格和以及OAuth2都做了较大改动,里面甚至将授权服务器模块都移除了,导致在配置同样功能时,花费了些时间研究新版本的底层原理,这里将一些学习经验分享给大家。
注意:由于框架不同版本改造会有些使用的不同,因此本次系列中使用基本框架是 spring-boo-3.3.0(默认引入的Spring Security是6.3.0),JDK版本使用的是19,本系列OAuth2的代码采用Spring Security6.3.0框架,所有代码都在oauth2-study项目上:https://github.com/forever1986/oauth2-study.git
目录
- 1 关键的类
- 1.1 Authentication
- 1.2 AuthenticationConverter
- 1.3 AuthenticationProvider
- 2 授权码模式的底层原理
- 3 授权码模式整体流程图
- 4 关键的Filter过滤器
- 4.1 OAuth2AuthorizationEndpointFilter(授权码code请求处理)
- 4.2 OAuth2TokenEndpointFilter(返回token)
- 4.3 OAuth2ClientAuthenticationFilter(客户端认证)
前面我们了解授权服务器的实现以及自定义客户端、自定义授权页面,也窥探了其中部分原理。这一章,我们通过授权码模式下,分析一下Spring Authrization Server的基本原理,同时对其中一些关键的Filter过滤器列出来,对后续实现功能会有帮助。我们知道Spring Authrization Server也是基于Spring Security 6基础上实现的,因此其关键功能都在其过滤器上面。下图红色框框的是Spring Authrization Server新增的过滤器,我们挑一些关键的解释一下

1 关键的类
在介绍关键的过滤器之前,有几个类需要先说明一下其作用,对后面阅读源码有很好的理解。
1.1 Authentication
Authentication其实是Spring Security的接口,主要就是封装认证信息,用于上下文传输,而在Spring Authrization Server中,有几个实现类比较重要:
- OAuth2AuthorizationCodeRequestAuthenticationToken:在授权码模式下,获取授权码时候封装的信息
- OAuth2AuthorizationConsentAuthenticationToken:在授权码模式下,跳转授权界面时,封装所需的信息
- OAuth2AuthorizationCodeAuthenticationToken:在请求token时,封装所需的信息
- OAuth2TokenExchangeAuthenticationToken:在交换token请求下,封装所需的信息
- OAuth2RefreshTokenAuthenticationToken:在刷新token请求下,封装所需的信息

1.2 AuthenticationConverter
AuthenticationConverter是一个request参数转换为Authentication的一个转换器,其中有几个实现类比较重要
- OAuth2AuthorizationCodeRequestAuthenticationConverter:在请求授权码时,将request的参数都封装为Authentication
- OAuth2AuthorizationConsentAuthenticationConverter:在请求授权码时,点击授权页面的确认后,将request的参数都封装为Authentication
- OAuth2AuthorizationCodeAuthenticationConverter:在请求token时,将request的参数都封装为Authentication
- OAuth2TokenExchangeAuthenticationConverter:在交换token时,将request的参数都封装为Authentication
- OAuth2RefreshTokenAuthenticationConverter:在刷新token时,将request的参数都封装为Authentication

1.3 AuthenticationProvider
AuthenticationProvider本身是Spring Security的接口,主要是用于验证结果,比如用户名密码登录等,这里Spring Authrization Server通过实现不同的AuthenticationProvider做不同验证,以下几个实现类比较重要:
- OAuth2AuthorizationCodeRequestAuthenticationProvider:主要用于授权码模式下,客户端的验证
- OAuth2AuthorizationConsentAuthenticationProvider:授权页面点击确认之后,客户端验证
- OAuth2AuthorizationCodeAuthenticationProvider:获取token接口时,客户端验证
- OAuth2TokenExchangeAuthenticationProvider:交换token接口时,客户端验证
- OAuth2RefreshTokenAuthenticationProvider:请求刷新token接口时,客户端验证

2 授权码模式的底层原理
1)我们从《系列之四-客户端–oauth2-client底层原理》中可知,客户端会访问/oauth2/authorize接口,这时候会有先到达OAuth2AuthorizationEndpointFilter过滤器,但是由于未登录,因此会被认定没有权限,不做处理,继续走过滤器链。


2)接着,请求会接着跳转到AuthorizationFilter过滤器(这是Spring Security的过滤器,做认证判断的),这时候会报AccessDeniedException异常,并由LoginUrlAuthenticationEntryPoint处理,跳转到Spring Security的登录界面

3)出现登录界面,进行登录之后,会继续请求/oauth2/authorize接口,这时候会被OAuth2AuthorizationEndpointFilter拦截,我们再看看OAuth2AuthorizationEndpointFilter的doFilterInternal方法

- 第一步:判断URI是否符合/oauth2/authorize
- 第二步:判断客户端信息是否符合要求
- 第三步:判断是否已经登录,没有登录,则由其它过滤器跳转到登录界面
- 第四步:判断是否已经授权,没有授权则跳转到登录界面
- 第五步:前面4步都没问题,则返回授权的code
下面我们将详细的源码调用过程列出来:

4)返回授权码给客户的之后,客户端会继续请求http://oauth-server:9000/oauth2/token获取token,而授权服务器的token由OAuth2TokenEndpointFilter过滤器处理
OAuth2TokenEndpointFilter是拦截"/oauth2/token"获取token请求,通过将request的参数封装为OAuth2AuthorizationCodeAuthenticationToken,然后调用OAuth2AuthorizationCodeAuthenticationProvider验证并生成token,通过后调用OAuth2AccessTokenResponseAuthenticationSuccessHandler返回token

3 授权码模式整体流程图

4 关键的Filter过滤器
从上面的整体流程,我们知道一些关键的Filter过滤器,这里罗列出来,后续讲解授权码其它功能时,会经常提到。
4.1 OAuth2AuthorizationEndpointFilter(授权码code请求处理)
在《系列之五 - 授权服务器–开篇》和本系列中分析过该过滤器。该过滤器专门处理/oauth2/authorize接口,在授权码模式下,该接口就是用于跳转到授权界面以及返回授权码的作用

4.2 OAuth2TokenEndpointFilter(返回token)
OAuth2TokenEndpointFilter是拦截"/oauth2/token"获取token请求,通过将request的参数封装为OAuth2AuthorizationCodeAuthenticationToken,然后调用OAuth2AuthorizationCodeAuthenticationProvider验证并生成token,通过后调用OAuth2AccessTokenResponseAuthenticationSuccessHandler返回token

4.3 OAuth2ClientAuthenticationFilter(客户端认证)
OAuth2ClientAuthenticationFilter主要是用于客户端认证,包括通过client_secret_basic、client_secret_post、client_secret_jwt、private_key_jwt、none、tls_client_auth和self_signed_tls_client_auth等不同认证方式。因此增加改拦截器用于客户端认证,其逻辑流程和OAuth2AuthorizationEndpointFilter前半部分有很大的相似,都是使用AuthenticationConverter转换参数,然后AuthenticationProvider进行验证。这块具体会在《系列之十五 - 高级特性–客户端认证方式》中详细说明。
结语:本章我们对Spring Authrization Server如何实现授权码模式以及自定义客户端信息进行源码解析,并了解了几个关键的Filter过滤器。有了这个基础,对接下来我们实现更为高级的授权服务器功能,并了解实现原理就变得更为容易。
相关文章:
基于Spring Security 6的OAuth2 系列之八 - 授权服务器--Spring Authrization Server的基本原理
之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级…...
蓝桥与力扣刷题(234 回文链表)
题目:给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。 示例 1: 输入:head [1,2,2,1] 输出:true示例 2: 输入&…...
Google C++ Style / 谷歌C++开源风格
文章目录 前言1. 头文件1.1 自给自足的头文件1.2 #define 防护符1.3 导入你的依赖1.4 前向声明1.5 内联函数1.6 #include 的路径及顺序 2. 作用域2.1 命名空间2.2 内部链接2.3 非成员函数、静态成员函数和全局函数2.4 局部变量2.5 静态和全局变量2.6 thread_local 变量 3. 类3.…...
Windows图形界面(GUI)-QT-C/C++ - QT Tab Widget
公开视频 -> 链接点击跳转公开课程博客首页 -> 链接点击跳转博客主页 目录 一、概述 1.1 什么是 QTabWidget? 1.2 使用场景 二、常见样式 2.1 选项卡式界面 2.2 动态添加和删除选项卡 2.3 自定义选项卡标题和图标 三、属性设置 3.1 添加页面&…...
【大数据技术】教程05:本机DataGrip远程连接虚拟机MySQL/Hive
本机DataGrip远程连接虚拟机MySQL/Hive datagrip-2024.3.4VMware Workstation Pro 16CentOS-Stream-10-latest-x86_64-dvd1.iso写在前面 本文主要介绍如何使用本机的DataGrip连接虚拟机的MySQL数据库和Hive数据库,提高编程效率。 安装DataGrip 请按照以下步骤安装DataGrip软…...
C++:结构体和类
在之前的博客中已经讲过了C语言中的结构体概念了,重复的内容在这儿就不赘述了。C中的结构体在C语言的基础上还有些补充,在这里说明一下,顺便简单地讲一下类的概念。 一、成员函数 结构体类型声明的关键字是 struct ,在C中结构体…...
MATLAB的数据类型和各类数据类型转化示例
一、MATLAB的数据类型 在MATLAB中 ,数据类型是非常重要的概念,因为它们决定了如何存储和操作数据。MATLAB支持数值型、字符型、字符串型、逻辑型、结构体、单元数组、数组和矩阵等多种数据类型。MATLAB 是一种动态类型语言,这意味着变量的数…...
UE求职Demo开发日志#19 给物品找图标,实现装备增加属性,背包栏UI显示装备
1 将用到的图标找好,放一起 DataTable里对应好图标 测试一下能正确获取: 2 装备增强属性思路 给FMyItemInfo添加一个枚举变量记录类型(物品,道具,装备,饰品,武器)--> 扩展DataT…...
C++泛型编程指南09 类模板实现和使用友元
文章目录 第2章 类模板 Stack 的实现2.1 类模板 Stack 的实现 (Implementation of Class Template Stack)2.1.1 声明类模板 (Declaration of Class Templates)2.1.2 成员函数实现 (Implementation of Member Functions) 2.2 使用类模板 Stack脚注改进后的叙述总结脚注2.3 类模板…...
使用MATLAB进行雷达数据采集可视化
本文使用轮趣科技N10雷达,需要源码可在后台私信或者资源自取 1. 项目概述 本项目旨在通过 MATLAB 读取 N10 激光雷达 的数据,并进行 实时 3D 点云可视化。数据通过 串口 传输,并经过解析后转换为 三维坐标点,最终使用 pcplayer 进…...
【Elasticsearch】allow_no_indices
- **allow_no_indices 参数的作用**: 该参数用于控制当请求的目标索引(通过通配符、别名或 _all 指定)不存在或已关闭时,Elasticsearch 的行为。 - **默认行为**: 如果未显式设置该参数,默认值为 …...
54【ip+端口+根目录通信】
上节课讲到,根目录起到定位作用,比如我们搭建一个php网站后,注册系统是由根目录的register.php文件执行,那么我们给这个根目录绑定域名https://127.0.0.1,当我们浏览器访问https://127.0.0.1/register.php时࿰…...
python算法和数据结构刷题[3]:哈希表、滑动窗口、双指针、回溯算法、贪心算法
回溯算法 「所有可能的结果」,而不是「结果的个数」,一般情况下,我们就知道需要暴力搜索所有的可行解了,可以用「回溯法」。 回溯算法关键在于:不合适就退回上一步。在回溯算法中,递归用于深入到所有可能的分支&…...
DeepSeek横空出世,AI格局或将改写?
引言 这几天,国产AI大模型DeepSeek R1,一飞冲天,在全球AI圈持续引爆热度,DeepSeek R1 已经是世界上最先进的 AI 模型之一,可与 OpenAI 的新 o1 和 Meta 的 Llama AI 模型相媲美。 DeepSeek-V3模型发布后,在…...
聚簇索引、哈希索引、覆盖索引、索引分类、最左前缀原则、判断索引使用情况、索引失效条件、优化查询性能
聚簇索引 聚簇索引像一本按目录排版的书,用空间换时间,适合读多写少的场景。设计数据库时,主键的选择(如自增ID vs 随机UUID)会直接影响聚簇索引的性能。 什么是聚簇索引? 数据即索引:聚簇索引…...
OpenAI 实战进阶教程 - 第四节: 结合 Web 服务:构建 Flask API 网关
目标 学习将 OpenAI 接入 Web 应用,构建交互式 API 网关理解 Flask 框架的基本用法实现 GPT 模型的 API 集成并返回结果 内容与实操 一、环境准备 安装必要依赖: 打开终端或命令行,执行以下命令安装 Flask 和 OpenAI SDK: pip i…...
python的pre-commit库的使用
在软件开发过程中,保持代码的一致性和高质量是非常重要的。pre-commit 是一个强大的工具,它可以帮助我们在提交代码到版本控制系统(如 Git)之前自动运行一系列的代码检查和格式化操作。通过这种方式,我们可以确保每次提…...
架构技能(四):需求分析
需求分析,即分析需求,分析软件用户需要解决的问题。 需求分析的下一环节是软件的整体架构设计,需求是输入,架构是输出,需求决定了架构。 决定架构的是软件的所有需求吗?肯定不是,真正决定架构…...
Linux环境下的Java项目部署技巧:安装 Nginx
Nginx 的简介: Nginx 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP / POP3 / SMTP 代理服务器。它可以作为网站静态资源的 web 服务器,也可以作为其他应用服务器的反向代理服务器。同时, Nginx 还具有负载均衡的功能。 N…...
前端 Vue 性能提升策略
一、引言 前端性能优化是确保 Web 应用快速响应和流畅用户体验的关键。对于使用 Vue.js 构建的应用,性能优化不仅涉及通用的前端技术,还包括针对 Vue 特性的特定优化措施。本文将从多个方面探讨如何全面提升前端和 Vue 应用的性能。 二、前端性能优化基础 1. 减少初始加载…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
Module Federation 和 Native Federation 的比较
前言 Module Federation 是 Webpack 5 引入的微前端架构方案,允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
redis和redission的区别
Redis 和 Redisson 是两个密切相关但又本质不同的技术,它们扮演着完全不同的角色: Redis: 内存数据库/数据结构存储 本质: 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能: 提供丰…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
