在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-method
为none
时上述四个参数:
{
"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-method
为none
时上述四个参数:
{
"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
等参数来生成,稍后会把构造机制分析一波。 -
redirectUri
当OAuth2AuthorizationRequest
被第三方平台收到后,第三方平台会回调这个URI来对授权请求进行相应,稍后也会来分析其机制。
authorizationRequestUri的构建机制
如果不显式提供authorizationRequestUri
就会通过OAuth2AuthorizationRequest
中的
responseType
clientId
scopes
state
redirectUri
additionalParameters
按照下面的规则进行拼接成authorizationUri
的参数串,参数串的key
和value
都要进行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
,有两种默认值login
、authorize
,当/oauth2/authorization
请求中包含了action
参数时会根据action
的值进行填充。 -
registrationId
这个就不用多说了。
4. 总结
通过对OAuth2AuthorizationRequest
请求对象的规则进行详细分析,我们应该能大致的知道的过滤器OAuth2AuthorizationRequestRedirectFilter
流程:
- 通过客户端配置构建
ClientRegistration
,后续可以进行持久化。 - 拦截
/oauth2/authorization
请求并构造OAuth2AuthorizationRequest
,然后重定向到authorizationRequestUri
进行请求授权。 - 第三方通过
redirect_uri
进行相应。
那么Spring Security OAuth2如何对第三方的回调相应进行处理呢?关注:码农小胖哥
为你揭晓这个答案。
关注公众号:码农小胖哥,获取更多资讯
个人博客:https://felord.cn