Spring Security 實戰(zhàn)干貨:客戶端OAuth2授權(quán)請求的入口在哪里
1. 前言
在Spring Security 實戰(zhàn)干貨:OAuth2 第三方授權(quán)初體驗一文中我先對 OAuth2.0 涉及的一些常用概念進(jìn)行介紹,然后直接通過一個 DEMO 來讓大家切身感受了 OAuth2.0 第三方認(rèn)證功能。今天我們來一步一步分析這其中的機(jī)制。
2. 抓住源頭
?http://localhost:8082/oauth2/authorization/gitee
上面這個請求 URL 是我們在上一篇文章中提到的客戶端進(jìn)行第三方認(rèn)證操作的起點,默認(rèn)格式為{baseUrl}/oauth2/authorization/{clientRegistrationId},其中clientRegistrationId代表著一個第三方標(biāo)識,可以是微信、支付寶等開放平臺,這里為gitee。用戶點擊了這個請求后就開始了授權(quán)之旅。假如大家都是從零開始的小白,肯定是要從這個入口來一步一步探尋其中的機(jī)制的。Spring Security 一定是攔截到了/oauth2/authorization后才啟用了 OAuth2 相關(guān)的處理邏輯。那就去抓住這個源頭!從源碼中搜索嘛!IDEA 快捷鍵CTRL SHIFT R?就可以全局搜索結(jié)果了。

不出所料找到了三個地方,記下來一個一個看!
OAuth2AuthorizationRequestRedirectWebFilter
先來看第一個OAuth2AuthorizationRequestRedirectWebFilter,它實現(xiàn)了 Spring Webflux 的WebFilter接口,這顯然是 Webflux 的東西,如果你用到 Webflux 的話這個會有用,但是不是現(xiàn)在我們用的。
DefaultOAuth2AuthorizationRequestResolver
第二個是干嘛的呢,從名稱上看著是一個默認(rèn) OAuth2 授權(quán)請求解析器。有時候名稱起的好就知道這個東西大致上干嘛的,不得不說優(yōu)秀框架細(xì)節(jié)抓的很好。它實現(xiàn)了接口OAuth2AuthorizationRequestResolver:
public?interface?OAuth2AuthorizationRequestResolver?{
???/**
????*?從HttpServletRequest對象中解析封裝?OAuth2AuthorizationRequest
????*/
???OAuth2AuthorizationRequest?resolve(HttpServletRequest?request);
???/**
????*?從HttpServletRequest對象以及clientRegistrationId中解析封裝?OAuth2AuthorizationRequest
????*/
???OAuth2AuthorizationRequest?resolve(HttpServletRequest?request,?String?clientRegistrationId);
}
也就是說當(dāng)我們請求/oauth2/authorization時,DefaultOAuth2AuthorizationRequestResolver?會從/oauth2/authorization對應(yīng)的HttpServletRequest中提取數(shù)據(jù)封裝到OAuth2AuthorizationRequest請求對象中做進(jìn)一步使用。
?注意:
/oauth2/authorization這個默認(rèn)攔截標(biāo)識也是可以自定義的。
OAuth2AuthorizationRequest
這里簡單提一下OAuth2AuthorizationRequest?封裝了我們上一文所描述的一些 OAuth2 相關(guān)概念參數(shù),后續(xù)這個請求類我們會用到它。
public?final?class?OAuth2AuthorizationRequest?implements?Serializable?{
????private?static?final?long?serialVersionUID?=?520L;
????private?String?authorizationUri;
????private?AuthorizationGrantType?authorizationGrantType;
????private?OAuth2AuthorizationResponseType?responseType;
????private?String?clientId;
????private?String?redirectUri;
????private?Set?scopes;
????private?String?state;
????private?Map?additionalParameters;
????private?String?authorizationRequestUri;
????private?Map?attributes;
????//?其它方法略
}
OAuth2AuthorizationRequestRedirectFilter
就剩下這個線索了,一看到它繼承了OncePerRequestFilter我就知道肯定是他了。甚至它的成員變量包含了用來解析 OAuth2 請求的OAuth2AuthorizationRequestResolver。到這里我們的路子就走對了,開始分析這個過濾器,下面是其核心過濾邏輯,這就是我們想要知道的 OAuth2 授權(quán)請求是如何被攔截處理的邏輯。
protected?void?doFilterInternal(HttpServletRequest?request,?HttpServletResponse?response,?FilterChain?filterChain)
??????throws?ServletException,?IOException?{
???try?{
??????OAuth2AuthorizationRequest?authorizationRequest?=?this.authorizationRequestResolver.resolve(request);
??????if?(authorizationRequest?!=?null)?{
?????????this.sendRedirectForAuthorization(request,?response,?authorizationRequest);
?????????return;
??????}
???}?catch?(Exception?failed)?{
??????this.unsuccessfulRedirectForAuthorization(request,?response,?failed);
??????return;
???}
???try?{
??????filterChain.doFilter(request,?response);
???}?catch?(IOException?ex)?{
??????throw?ex;
???}?catch?(Exception?ex)?{
??????//?Check?to?see?if?we?need?to?handle?ClientAuthorizationRequiredException
??????Throwable[]?causeChain?=?this.throwableAnalyzer.determineCauseChain(ex);
??????ClientAuthorizationRequiredException?authzEx?=?(ClientAuthorizationRequiredException)?this.throwableAnalyzer
?????????.getFirstThrowableOfType(ClientAuthorizationRequiredException.class,?causeChain);
??????if?(authzEx?!=?null)?{
?????????try?{
????????????OAuth2AuthorizationRequest?authorizationRequest?=?this.authorizationRequestResolver.resolve(request,?authzEx.getClientRegistrationId());
????????????if?(authorizationRequest?==?null)?{
???????????????throw?authzEx;
????????????}
????????????this.sendRedirectForAuthorization(request,?response,?authorizationRequest);
????????????this.requestCache.saveRequest(request,?response);
?????????}?catch?(Exception?failed)?{
????????????this.unsuccessfulRedirectForAuthorization(request,?response,?failed);
?????????}
?????????return;
??????}
??????if?(ex?instanceof?ServletException)?{
?????????throw?(ServletException)?ex;
??????}?else?if?(ex?instanceof?RuntimeException)?{
?????????throw?(RuntimeException)?ex;
??????}?else?{
?????????throw?new?RuntimeException(ex);
??????}
???}
}
doFilterInternal方法對應(yīng)的流程如下:

根據(jù)這個流程,如果要搞清楚 Spring Security OAuth2 是如何重定向到第三方的話就要深入研究sendRedirectForAuthorization方法,基于篇幅原因我會在下一篇進(jìn)行分析。
3. 總結(jié)
今天我們從源頭一步一步找到 OAuth2 授權(quán)的處理入口,并初步分析了幾個關(guān)鍵組件的作用以及核心攔截器的攔截邏輯。后續(xù)我們將層層深入循序漸進(jìn)地搞清楚其運作流程,不要走開,鎖定公眾號:碼農(nóng)小胖哥?循序漸進(jìn)學(xué)習(xí) Spring Security OAuth2 。

往期推薦
﹀
﹀
﹀
深度內(nèi)容
推薦加入




