Spring Security 实战干货:OAuth2登录获取Token的核心逻辑

Stella981
• 阅读 532

Spring Security 实战干货:OAuth2登录获取Token的核心逻辑

作者 | 码农小胖哥

来源 | https://mp.weixin.qq.com/s/zdTBdSVunqwVGx-spHjLjw

1. 前言

在上一篇Spring Security 实战干货:OAuth2 授权回调的核心认证流程中,我们讲了当第三方同意授权后会调用redirectUri发送回执给我们的服务器。我们的服务器拿到一个中间授信凭据会再次进行认证,目的是为了获取Token。而这个逻辑由OAuth2LoginAuthenticationProvider负责,经过上一文的分析后我们发现获取Token的具体逻辑由OAuth2AuthorizationCodeAuthenticationProvider来完成,今天就把它的流程搞清楚,来看看Spring Security OAuth2 认证授权获取Token的具体步骤。

注意:本Spring Security干货系列教程的 OAuth2 相关部分是在Spring Security 5.x版本的。

2. OAuth2AuthorizationCodeAuthenticationProvider

该类是AuthenticationProvider针对OAuth 2.0Authorization Code Grant模式的实现。关于AuthenticationProvider有必要简单强调一下,它已经多次在Spring Security 干货系列中出现,十分重要!一定要去看看相关的分析和使用,它是你根据业务扩展认证方式渠道的重要入口。

2.1 OAuth2AccessTokenResponseClient

在该实现中包含了一个OAuth2AccessTokenResponseClient成员变量,它抽象了通过tokenUri端点从认证服务器获取Token的细节。你可以根据OAuth 2.0常用的四种模式来进行实现它, 以达到根据不同的策略来获取Token的能力。

Spring Security 实战干货:OAuth2登录获取Token的核心逻辑 OAuth 2.0 四种模式的对应实现

Spring Security 5OAuth 2.0登录的配置中默认使用DefaultAuthorizationCodeTokenResponseClient。如果你想使用自定义实现的话可以通过HttpSecurity来配置:

        @Override        protected void configure(HttpSecurity http) throws Exception {            http.oauth2Login()                    .tokenEndpoint()                // 注入自定义的 OAuth2AccessTokenResponseClient                    .accessTokenResponseClient(authorizationCodeTokenResponseClient);            // 其它省略        }

接下来我们看看DefaultAuthorizationCodeTokenResponseClient实现的获取Token的逻辑:

@Overridepublic OAuth2AccessTokenResponse getTokenResponse(OAuth2AuthorizationCodeGrantRequest authorizationCodeGrantRequest) {   Assert.notNull(authorizationCodeGrantRequest, "authorizationCodeGrantRequest cannot be null");// 1. 封装调用tokenUri所需要的请求参数RequestEntity   RequestEntity<?> request = this.requestEntityConverter.convert(authorizationCodeGrantRequest);   ResponseEntity<OAuth2AccessTokenResponse> response;   try {   // 2. 通过RestTemplate 发起请求获取 OAuth2AccessTokenResponse      response = this.restOperations.exchange(request, OAuth2AccessTokenResponse.class);   } catch (RestClientException ex) {      OAuth2Error oauth2Error = new OAuth2Error(INVALID_TOKEN_RESPONSE_ERROR_CODE,            "An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: " + ex.getMessage(), null);      throw new OAuth2AuthorizationException(oauth2Error, ex);   }  // 3. 解析 ResponseEntity 组织返回值 OAuth2AccessTokenResponse   OAuth2AccessTokenResponse tokenResponse = response.getBody();   if (CollectionUtils.isEmpty(tokenResponse.getAccessToken().getScopes())) {      // originally requested by the client in the Token Request      tokenResponse = OAuth2AccessTokenResponse.withResponse(tokenResponse)            .scopes(authorizationCodeGrantRequest.getClientRegistration().getScopes())            .build();   }   return tokenResponse;}

这里的方式跟我另一个开源项目Payment Spring Boot的请求方式异曲同工,都是三个步骤:

  1. 组织参数 RequestEntity

  2. RestOperations发起请求。

  3. 解析 ResponseEntity组织返回值。

如果有些的OAuth 2.0认证服务器获取Token的方式比较特殊你可以自行实现OAuth2AccessTokenResponseClient

3. 总结

OAuth2AccessTokenResponseClientOAuth2AuthorizationCodeAuthenticationProvider的核心要点。搞清楚它的作用和机制就可以了。这里我们总结一下OAuth2AuthorizationCodeAuthenticationProvider的认证过程:

  1. 检测未授信 OAuth2AuthorizationCodeAuthenticationToken的状态是否合法。

  2. 通过 OAuth2AccessTokenResponseClient请求 OAuth 2.0认证服务器获取 Token等信息。

  3. 组装认证过的授信 OAuth2AuthorizationCodeAuthenticationToken返回。

到此OAuth 2.0的登录流程就搞清楚了,读者可通过系列文章进行学习批判。我是:码农小胖哥,多多关注,获取实用的编程干货。

推荐关注本文作者:码农小胖哥

分享高质量编程知识,探讨IT人生

技术干货,实战技巧,面试技巧,前沿资讯一个都不能少

往期推荐

[

上云上的差点破产是什么体验?

](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzAxODcyNjEzNQ%3D%3D%26mid%3D2247525084%26idx%3D1%26sn%3D1eae322f61ef4df3dd4e2f2d418ae6a8%26chksm%3D9bd3cf44aca446529ecd95944a23e460fd0b263937f180b5bb76580c43003214601f7ecc6855%26scene%3D21%23wechat_redirect)

[

本科毕业出国率下降,考研or保研?条条大路通「内卷」

](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzAxODcyNjEzNQ%3D%3D%26mid%3D2247525084%26idx%3D3%26sn%3Dff71f7f99aa870827dab1989ce51efcf%26chksm%3D9bd3cf44aca44652802d0cf01445cb213d37174ee2fb47b20404275a1c7a7d0f561de35f8635%26scene%3D21%23wechat_redirect)

[

一个员工的离职,背后都意味着什么?

](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzAxODcyNjEzNQ%3D%3D%26mid%3D2247524991%26idx%3D1%26sn%3D3dda3739c5f60097737f7068613cdfa2%26chksm%3D9bd3cfe7aca446f152f58527399b4d05146f808e4e7ae242800f0b2c7e4d40a4c141721e0d4a%26scene%3D21%23wechat_redirect)

[

彻底解决 gcr、quay、DockerHub 镜像下载难题!

](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzAxODcyNjEzNQ%3D%3D%26mid%3D2247524991%26idx%3D2%26sn%3D054d493e27f6db33de19919079ba689c%26chksm%3D9bd3cfe7aca446f1bfaf227c31aea9b821a5c523e45fc73e77039e4f4b920f038d5a99c29b71%26scene%3D21%23wechat_redirect)

[

合格的后端Coder都应该写好UT和Mock测试

](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzAxODcyNjEzNQ%3D%3D%26mid%3D2247524934%26idx%3D1%26sn%3D2ba3aa25b16beb8fb03f68e2dbd17d18%26chksm%3D9bd3cfdeaca446c88e1de0fc05bc7471fc3acc1a76d73537358841baa73a0a90c58da3317685%26scene%3D21%23wechat_redirect)

[

Spring Boot 2.4.3、2.3.9 版本发布,你准备好了吗?

](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fmp.weixin.qq.com%2Fs%3F__biz%3DMzAxODcyNjEzNQ%3D%3D%26mid%3D2247524934%26idx%3D2%26sn%3D189f55492ca19fdeb44215e1af0ad5d7%26chksm%3D9bd3cfdeaca446c8bf9db6701d3a3c2d9bc0676db96deeb21295d627874a1536eca675bed94e%26scene%3D21%23wechat_redirect)

本文分享自微信公众号 - 程序猿DD(didispace)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Stella981 Stella981
2年前
Android So动态加载 优雅实现与原理分析
背景:漫品Android客户端集成适配转换功能(基于目标识别(So库35M)和人脸识别库(5M)),导致apk体积50M左右,为优化客户端体验,决定实现So文件动态加载.!(https://oscimg.oschina.net/oscnet/00d1ff90e4b34869664fef59e3ec3fdd20b.png)点击上方“蓝字”关注我
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这