之所以想写这一系列,是因为之前工作过程中使用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过滤器。有了这个基础,对接下来我们实现更为高级的授权服务器功能,并了解实现原理就变得更为容易。