Spring Security 实战干货:OAuth2授权请求是如何构建并执行的

码农小胖哥 2020-11-11 10:09:00
spring Security 实战 干货 oauth2


Spring Security 实战干货:客户端OAuth2授权请求的入口中我们找到了拦截OAuth2授权请求入口/oauth2/authorization的过滤器OAuth2AuthorizationRequestRedirectFilter,并找到了真正发起OAuth2授权请求的方法sendRedirectForAuthorization。但是这个方法并没有细说,所以今天接着上一篇把这个坑给补上。

2. sendRedirectForAuthorization

这个sendRedirectForAuthorization方法没多少代码,它的主要作用就是向第三方平台进行授权重定向访问。它所有的逻辑都和OAuth2AuthorizationRequest有关,因此我们对OAuth2AuthorizationRequest进行轻描淡写是不行的,我们必须掌握OAuth2AuthorizationRequest是怎么来的,干嘛用的。

OAuth2AuthorizationRequestResolver

这就需要去分析解析类OAuth2AuthorizationRequestResolver,其核心方法有两个重载,这里分析一个就够了。

@Override
public OAuth2AuthorizationRequest resolve(HttpServletRequest request) {
// registrationId是通过uri路径参数/oauth2/authorization/{registrationId}获得的
String registrationId = this.resolveRegistrationId(request);
// 然后去请求对象request中提取key为action的参数,默认值是login
String redirectUriAction = getAction(request, "login");
// 然后进入根本的解析方法
return resolve(request, registrationId, redirectUriAction);
}

上面方法里面的resolve(request, registrationId, redirectUriAction)方法才是最终从/oauth2/authorization提取OAuth2AuthorizationRequest的根本方法。代码太多但是我尽量通俗易懂的来进行图解。resolve方法会根据不同的授权方式(AuthorizationGrantType)来组装不同的OAuth2AuthorizationRequest

3. OAuth2AuthorizationRequest

接下来就是OAuth2.0协议的核心重中之重了,可能以后你定制化的参考就来自这里,这是圈起来要考的知识点。我会对OAuth2AuthorizationRequestResolver在各种授权方式下的OAuth2AuthorizationRequest对象的解析进行一个完全的总结归纳。大致分为以下两部分:

3.1 由AuthorizationGrantType决定的

在不同AuthorizationGrantType下对OAuth2AuthorizationRequest的梳理。涉及到的成员变量有:

  • authorizationGrantType ,来自配置spring.security.client.registration.{registrationId}.authorizationGrantType
  • responseType , 由authorizationGrantType 的值决定,参考下面的JSON。
  • additionalParameters,当authorizationGrantType值为authorization_code时需要额外的一些参数,参考下面JSON 。
  • attributes,不同的authorizationGrantType存在不同的属性。
其中类似 {registrationId} 的形式表示 {registrationId}是一个变量,例如 registrationId=gitee

在OAuth2客户端配置spring.security.client.registration.{registrationId}的前缀中有以下五种情况。

scope 不包含openid而且client-authentication-method不为none时上述四个参数:

{
"authorizationGrantType": "authorization_code",
"responseType": "code",
"additionalParameters": {},
"attributes": {
"registration_id": "{registrationId}"
}
}

scope 包含openid而且client-authentication-method不为none时上述四个参数:

{
"authorizationGrantType": "authorization_code",
"responseType": "code",
"additionalParameters": {
"nonce": "{nonce}的Hash值"
},
"attributes": {
"registration_id": "{registrationId}",
"nonce": "{nonce}"
}
}

scope不包含openid而且client-authentication-methodnone时上述四个参数:

{
"authorizationGrantType": "authorization_code",
"responseType": "code",
"additionalParameters": {
"code_challenge": "{codeVerifier}的Hash值",
// code_challenge_method 当不是SHA256可能没有该key
"code_challenge_method": "S256(如果是SHA256算法的话)"
},
"attributes": {
"registration_id": "{registrationId}",
"code_verifier": "Base64生成的安全{codeVerifier}"
}
}

scope包含openid而且client-authentication-methodnone时上述四个参数:

{
"authorizationGrantType": "authorization_code",
"responseType": "code",
"additionalParameters": {
"code_challenge": "{codeVerifier}的Hash值",
// code_challenge_method 当不是SHA256可能没有该key
"code_challenge_method": "S256(如果是SHA256算法的话)",
"nonce": "{nonce}的Hash值"
},
"attributes": {
"registration_id": "{registrationId}",
"code_verifier": "Base64生成的安全{codeVerifier}",
"nonce": "{nonce}"
}
}

implicit下要简单的多:

{
"authorizationGrantType": "implicit",
"responseType": "token",
"attributes": {}
}

3.2 固定规则部分

上面是各种不同AuthorizationGrantType下的OAuth2AuthorizationRequest的成员变量个性化取值策略, 还有几个参数的规则是固定的:

  • clientId 来自于配置,是第三方平台给予我们的唯一标识。
  • authorizationUri来自于配置,用来构造向第三方发起的请求URL。
  • scopes 来自于配置,是第三方平台给我们授权划定的作用域,可以理解为角色。
  • state 自动生成的,为了防止csrf 攻击。
  • authorizationRequestUri 向第三方平台发起授权请求的,可以直接通过OAuth2AuthorizationRequest的构建类来设置或者通过上面的authorizationUri等参数来生成,稍后会把构造机制分析一波。
  • redirectUriOAuth2AuthorizationRequest被第三方平台收到后,第三方平台会回调这个URI来对授权请求进行相应,稍后也会来分析其机制。

authorizationRequestUri的构建机制

如果不显式提供authorizationRequestUri就会通过OAuth2AuthorizationRequest中的

  • responseType
  • clientId
  • scopes
  • state
  • redirectUri
  • additionalParameters

    按照下面的规则进行拼接成authorizationUri的参数串,参数串的keyvalue都要进行URI编码。

authorizationUri?response_type={responseType.getValue()}&client_id={clientId}&scope={scopes元素一个字符间隔}&state={state}&redirect_uri={redirectUri}&{additionalParameter展开进行同样规则的KV参数串}

然后OAuth2AuthorizationRequestRedirectFilter负责重定向到authorizationRequestUri向第三方请求授权。

redirectUri

第三方收到响应会调用redirectUri,回调也是有一定默认规则的,它遵循{baseUrl}/{action}/oauth2/code/{registrationId}的路径参数规则。

  • baseUrl 是从我们/oauth2/authorization请求中提取的基础请求路径。
  • action,有两种默认值loginauthorize ,当/oauth2/authorization请求中包含了action参数时会根据action的值进行填充。
  • registrationId 这个就不用多说了。

4. 总结

通过对OAuth2AuthorizationRequest请求对象的规则进行详细分析,我们应该能大致的知道的过滤器OAuth2AuthorizationRequestRedirectFilter流程:

  1. 通过客户端配置构建ClientRegistration,后续可以进行持久化。
  2. 拦截/oauth2/authorization请求并构造OAuth2AuthorizationRequest,然后重定向到authorizationRequestUri进行请求授权。
  3. 第三方通过redirect_uri进行相应。

那么Spring Security OAuth2如何对第三方的回调相应进行处理呢?关注:码农小胖哥 为你揭晓这个答案。

关注公众号:Felordcn 获取更多资讯

个人博客:https://felord.cn

版权声明
本文为[码农小胖哥]所创,转载请带上原文链接,感谢
https://segmentfault.com/a/1190000037793599

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云