首页 > 编程语言 >SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)

SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)

时间:2022-12-01 17:35:17浏览次数:46  
标签:请求 自定义 grant SpringSecurity token 源码 SpringSecurityOAuth2 tokenRequest

前言

周末闲来无事,谢谢自己的项目,然后想把老的授权模式改造一下,老的是基于SpringSecurity的实现,想升级为SpringSecurity OAuth2模式,于是看了下之前搭建的SpringSecurity OAuth2的框架,代码嫁接进来基本上是没问题的,嫁接进来后满足SpringSecurity OAuth2默认提供的5种授权模式,然后外加一套自定义账号密码登录模式(原有的一套账号密码模式用作Admin管理后台系统登录,这一套自定义的用于客户端的账号密码登录)、验证码登录模式,看了之前写的文章SpringSecurityOAuth2授权流程源码分析,发现文章末尾有提到补充其他授权模式的文章,那么借此机会补充下!前提是按照SpringSecurityOauth2自定义授权模式这篇文章把自定义验证码模式搞定!

主流程框架

SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_ide

流程分析

SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_其他_02
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_ide_03

这是整个请求,请求包括两部分,一部分是请求头中的Authorization和请求体中的参数,参数中grant_type尤为重要,关于grant_type参数可以看看往期文章SpringSecurityOauth2自定义授权模式

1.请求开始
当客户端发起请求后,请求会经过一系列过滤器,WebAsyncManagerIntegrationFilter、SecurityContextPersistenceFilter、HeaderWriterFilter、CsrfFilter(关闭后不经过)、LogoutFilter、BasicAuthenticationFilter、OAuth2ClientAuthenticationProcessingFilter、UsernamePasswordAuthenticationFilter、DefaultLoginPageGeneratingFilter。。。。等其他,其中BasicAuthenticationFilter会过滤会执行一些逻辑,当然其他过滤器也会执行,直到最后ExceptionTranslationFilter中的决定器会根据投票器的结果判断请求能否到达Controller

2.BasicAuthenticationFilter在干嘛?
我们来到BasicAuthenticationFilter过滤器的doFilterInternal方法,这个方法中下面代码

Authentication authResult = this.authenticationManager.authenticate(authRequest);

这行代码会做一件有趣的事情,这是我在这次权限升级成SpringSecurity Oauth2的时候发现的

我将之前搭建的SpringSecurity OAuth2的代码嫁接过来后,在没有对代码更改的情况下,又将之前配套的表导入到数据库,但是其中有一张表出了问题oauth_client_details,就是这张表,之前的表名是oauth_client_details,我在前面加了项目名作为前缀,发现授权流程请求失败了,提示没有权限,于是调试了下,发现既然真的是这个表名的问题,原因是请求在没到Controller之前被BasicAuthenticationFilter拦截下来了,然后执行上面那段代码后通过请求头中Authorization的Username和Password到oauth_client_details这张表中查询端点信息去了,但是我这里表名发生变化了,所以抛出异常被捕获,导致请求没被放行。下面代码就是到数据库查询端点信息的
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_自定义_04
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_java_05
当把表名恢复过来后,整个流程就可以了!顺着这个有趣问题好好回味一下整个授权流程!

3.请求放行
当把表名恢复过来后,请求就被放行了,这时请求到达了/oauth/token这个Controller上面,看过上下文的朋友会发现这个/oauth/token请求和SpringSecurity OAuth2默认提供的账号密码授权模式是一样的,对就是一样的,不但这个自定义的短信验证码授权流程是一样的其他的包括SpringSecurity OAuth2的其他模式还有我另外一个客户端的自定义账号密码授权模式也都是同一个只是/oauth/token中调用的Provider和Granter不同,SpringSecurity OAuth2默认的账号密码模式的Provider是DaoAuthenticationProvider,Granter是ResourceOwnerPasswordTokenGranter,而自定义的短信验证码这是调用我们自己编写的SmsVerificationCodeAuthenticationProvider和SmsVerificationCodeTokenGranter

4./oauth/token

对应图中的TokenEndpoint

SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_其他_06

核心流程就是这上面几个框框!

if (!(principal instanceof Authentication))

校验下入参信息!

对应图中的ClientDetails和TokenRequest

ClientDetails authenticatedClient = getClientDetailsService().loadClientByClientId(clientId);
TokenRequest tokenRequest = getOAuth2RequestFactory().createTokenRequest(parameters, authenticatedClient);

这两行实际上就是构建端点信息,也就是根据请求头中Authorization的Username和Password去数据库中查询的,这里我觉得挺奇怪的,在上面的BasicAuthenticationFilter过滤器中查询过一次,这里还TM查询两次,有点不明白这种设计!

oAuth2RequestValidator.validateScope(tokenRequest, authenticatedClient);

检验一下端点信息中的
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_java_07
重点来了

OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);

其实关于这行代码已经在SpringSecurityOAuth2授权流程源码分析中讲过了,但是感觉并不是很详细,下面进行补充!

重中之重

OAuth2AccessToken token = getTokenGranter().grant(tokenRequest.getGrantType(), tokenRequest);

getTokenGranter()

对应图中TokenGrande

getTokenGranter()得到okenGranter
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_自定义_08
这里得到了我们系统中配置的授权模式,总共7个,前面5个是SpringSecurity OAuth2默认提供的,下面两个是自定义的!

tokenRequest.getGrantType()
得到请求参数中的grant_type
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_spring_09
.grant
最后在执行这个方法,如下,因为getTokenGranter()得到的TokenGranter,然后调用grant方法
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_java_10
上面有个重要的入口

return delegate.grant(grantType, tokenRequest);

delegate为CompositeTokenGranter中的方法
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_ide_11
这里就是通过grantType循环在tokenGranters(配置好的授权模式)中找到匹配类型的Granter,核心代码如下

OAuth2AccessToken grant = granter.grant(grantType, tokenRequest);

此时匹配到的granter为SmsVerificationCodeTokenGranter,调用.grant(grantType, tokenRequest);方法,grant方法并不在SmsVerificationCodeTokenGranter中,而是在SmsVerificationCodeTokenGranter继承的AbstractTokenGranter中如下
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_ide_12
进入grant方法后通过

return getAccessToken(client, tokenRequest);

调用
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_ide_13
进入这个getAccessToken后调用了getOAuth2Authentication(client, tokenRequest)这个方法,然而getOAuth2Authentication方法在SmsVerificationCodeTokenGranter中重写了,所以执行逻辑来到了SmsVerificationCodeTokenGranter中的getOAuth2Authentication方法
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_java_14
其中这行代码则将SpringSecurity中的部分知识联系起来了。

userAuth = authenticationManager.authenticate(userAuth);

上面代码执行进入下面这部分代码
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_java_15

if (!provider.supports(toTest)) {

这里在循环系统中配置的Providers,然后通过每个Provider的supports进行匹配
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_其他_16
那么这里SmsVerificationCodeAuthenticationProvider被选中!
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_ide_17
得到provider为SmsVerificationCodeAuthenticationProvider!

result = provider.authenticate(authentication);

调用SmsVerificationCodeAuthenticationProvider中的authenticate方法
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_其他_18

UserDetails user = clientUserDetailsService.loadUserByPhone(principal.get(SecurityConstants.PHONE_PARAMETER));

关于这行代码,我是真的不想说了,从SpringSecurity的第一篇文章到此,讲过无数次了,不知道的看往期文章!

 SmsVerificationCodeAuthenticationToken smsVerificationCodeAuthenticationToken = new SmsVerificationCodeAuthenticationToken(user, user.getAuthorities());
smsVerificationCodeAuthenticationToken.setDetails(authenticationToken.getDetails());
return smsVerificationCodeAuthenticationToken;

封装用户信息,得到Authentication!

对应图中Authentication

一路返回到调用处SmsVerificationCodeTokenGranter中
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_自定义_19
Authentication中的用户信息信息已经得到了,然后在将端点信息和请求信息封装到OAuth2Request中

对应图中OAuth2Request

OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);

然后将OAuth2Request和Authentication封装到OAuth2Authentication中

new OAuth2Authentication(storedOAuth2Request, userAuth);

对应图中OAuth2Authentication

这里返回的是OAuth2Authentication对象,别忘了,这里一些列的操作都要回到AbstractTokenGranter的getAccessToken方法
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_java_20
执行tokenServices.createAccessToken得到OAuth2AccessToken,进入createAccessToken方法
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_ide_21

OAuth2AccessToken existingAccessToken = tokenStore.getAccessToken(authentication);

这行代码时在Redis的缓存中检查Token,如果存在且没过期,那么直接返回原有的token重置一下过期时间。如果不存在那么往下

OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);

在进入createAccessToken方法,我们得到OAuth2AccessToken

对应图中OAuth2AccessToken

SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_自定义_22
通过accessTokenEnhancer.enhance(token, authentication) : token;将授权信息编码,也就是转换成JWT

SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_ide_23
那么经过编码后得到token

tokenStore.storeAccessToken(accessToken, authentication);

执行上面代码将Token刷新到Redis中去!并将Token原路返回到TokenEndpoint中

然后我们代码就回到了TokenEndpoint中的/oauth/token请求
SpringSecurityOAuth2授权流程源码分析(自定义验证码模式)_ide_24
最后写回到Response中去,响应到客户端!

标签:请求,自定义,grant,SpringSecurity,token,源码,SpringSecurityOAuth2,tokenRequest
From: https://blog.51cto.com/u_15899048/5903406

相关文章

  • 《安富莱嵌入式周报》第293期:SEGGER开源其C/C++库源码emRun,丰富EMC电磁兼容资,OTA开源
    往期周报汇总地址:http://www.armbbs.cn/forum.php?mod=forumdisplay&fid=12&filter=typeid&typeid=104 视频版:https://www.bilibili.com/video/BV1ND4y1v7ik/ 1、......
  • HTML5 data-* 自定义属性
    HTML5data-*自定义属性  在jQuery的attr与prop提到过在IE9之前版本中如果使用property不当会造成内存泄露问题,而且关于Attribute和Property的区别也让人十分头痛,在......
  • 直播app系统源码,简单易上手的进度条
    直播app系统源码,简单易上手的进度条第一步:安装NProgress$npminstall--savenprogress ​第二步:在main.js文件中导入NProgress包对应的JS和CSS//导入NProgress......
  • 自定义样式与主题
    #样式与主题(重点)##01_样式样式:主要作用于控件上的,修饰控件的一些属性;自定义样式:<?xmlversion="1.0"encoding="utf-8"?><resourcesxmlns:android="http://schemas.androi......
  • OCC gp_Ax2源码记录
    gp_Ax2代表一个三维右手坐标系。坐标系包括以下内容:-原点(Locationpoint)-3个正交的单位向量,在OCC中分别称为"XDirection"(后文统称X),"YDirection"(后文统称Y)......
  • 在CentOS编译Git源码
    ​​Git​​​是一个​​免费的开源​​分布式版本控制系统,旨在处理从小到小到的所有内容具有速度和效率的超大型项目。Git​​易于学习​​​,​​占用空间很小,性能快如闪......
  • JavaScript中的Error错误对象与自定义错误类型
    ErrorError是JavaScript语言中的一个标准的内置对象,专门用于处理JS开发中的运行时错误。当我们的JS代码在运行过程中发生错误的话,就会抛出Error对象,整个程序将会中断在错......
  • 自定义类似VlookUp函数的包含性匹配
    使用场景介绍:基础数据表Sheet1:  代查找匹配的表Sheet2:【说明】代查找工作表中的规格,只是基础工作表中规格的一部分,是完全被包含的关系,只要是完全被包含,就匹配其代......
  • OCC gp_Ax1源码阅读记录
    gp_Ax1描述了一个三维轴。轴包含以下内容:-原点(Locationpoint)-单位向量(称作"Direction"或"mainDirection")轴通常有以下用途:-描述三维几何体(例如:旋转体的轴)......
  • 实战 | OpenCV带掩码(mask)的模板匹配使用技巧与演示(附源码)
    导读本文将重点介绍OpenCV带掩码(mask)的模板匹配使用技巧与演示。(公众号:OpenCV与AI深度学习) 背景介绍  在使用模板匹配时,一些特定情况中我们并不需要将整个模板图......