Grant類型以及它們各自的适用場景的擷取Access Token的方式,我想很多之前沒有接觸過OAuth
2.0的讀者朋友們依然會有“不值所雲” 之感,是以在介紹的内容中,我們将采用執行個體示範的方式對Implicit和Authorization
Code這兩種常用的Authorization Grant作深入介紹。本章着重介紹Implicit Authorization Grant。
假設我們的用戶端應用內建了Windows
Live Connect API認證服務,并且在成功取得使用者授權并得到Access Token之後調用相應的Web
API擷取目前登入使用者的個人資訊。一般來說,Implicit類型的Authorization Grant大都被将浏覽器作為執行上下文的用戶端應用采用,換句話說,這樣的用戶端就是在浏覽器中執行的JavaScript程式。下圖展現了這樣一個采用Implicit類型的Authorization Grant的用戶端應用取得授權、得到Access Token并最終擷取到受保護資源(登入使用者個人資訊)的完整流程。

如右圖所示,使用者會先被用戶端應用重定向到授權伺服器(login.live.com),具體的位址為“https://login.live.com/oauth20_authorize.srf”。相關的輸入參數通過查詢字元串的形式,必須提供的參數包含在如下的清單中。
response_type: 表示請求希望擷取的對象類型,在此我們希望擷取的是Access Token,是以這裡指定的值為“token”。
redirect_uri: 表示授權伺服器在獲得使用者授權并完成對使用者的認證之後重定向的位址,Access Token就以Hash(#)的方式附加在該URL後面。用戶端應用利用這個位址接收Access Token。
client_id: 唯一辨別被授權用戶端應用的ClientID。
scope:
表示授權的範圍,如果采用“wl.signin”意味着允許使用者從用戶端應用直接登入到Live
Services,如果Scope為“wl.basic”則表示運作用戶端應用擷取聯系人資訊。如果讀者朋友希望了解Windows Live
Connect具體支援那些Scope,可以查閱Windows Live Connect API的官方文檔。
如果目前使用者尚未登入到Windows
Live Services,登入視窗将會出現,當使用者輸入正确Windows
Live帳号和密碼并成功通過認證之後,浏覽器其上會出現如下圖所示的授權頁面,具體需要授予的權限集取決于上面介紹的Scope參數。我們點選“Yes”按鈕完成授權,成功授權之後,這個的授權頁面在後續的請求中将不會再出現。
授權伺服器在擷取使用者的授權之後,會生成一個Access
Token。接下來,它會提取請求中指定的重定向位址(即redirect_uri參數),然後将生成的Access
Token以Hash(#)的形式附加在該位址後面,最終針對這個攜帶有Access
Token的新位址傳回一個重定向的響應。如第一張圖所示,我們采用的重定向位址為“http://www.myapp.com/capturetoken”,那麼最終浏覽器将會重定向到位址“http://www.myapp.com/capturetoken#acess_token={accesstoken}”上。
這個重定向位址對應着用戶端應用需要擷取授權資源的頁面,該頁面可以直接從代表目前位址的URL中獲得Access Token,并利用它來擷取目标資源。對于我們的例子來說,它需要擷取目前Windows Live帳号的基本資訊,請求的位址為“https://apis.live.net/v5.0/me”,Access Token以查詢字元串的形式(“?access_token={accesstoken}”)提供給資源伺服器,後者據此驗證請求的合法性并在驗證成功的情況下将目前使用者的基本資訊以JSON的形式傳回給用戶端應用。
假設我們在Windows Live Connect建立了一個采用“https://www.artech.com”作為域名的應用,我們需要利用hosts檔案(“%windir%\System32\drivers\etc\hosts”)将此域名映射為本機的IP位址(127.0.0.1),具體的映射腳本如下所示。除此之外,由于我們采用HTTPS并且采用本地IIS作為宿主,是以我們需要為Web
API應用所在的站點添加一個HTTPS綁定。
在具體介紹認證實作原理之前,我們不妨先來示範一下最終達到的效果。我們在ASP.NET Web
API應用中定義了如下一個繼承自ApiController的DemoController,它具有唯一一個用于擷取目前登入使用者個人基本資訊的Action方法GetProfile。在該方法中,它通過我們定義的擴充方法TryGetAccessToken從目前請求中提取Access
Token,然後利用它調用Windows Live Connect提供的Web
API(https://apis.live.net/v5.0/me)。
內建Windows Live Connect認證的實作最終是通過應用在DemoController類型上的AuthenticateAttribute特性來完成的,這是一個AuthenticationFilter,作為參數的URL指向一個用于擷取和轉發Access Token的Web頁面。現在我們直接利用浏覽器來調用定義在DemoController中的Action方法GetProfile,如果目前使用者尚未登入到Windows
Live,浏覽器會自動重定向到Windows Live的登入界面。當我們輸入正确Windows
Live帳号和密碼後,目前使用者的基本資訊以JSON格式顯示在浏覽器上(如果尚未對該應用進行授權,如上圖所示的頁面會呈現出來),具體的效果如下圖所示。
應用在DemoController上的AuthenticateAttribute特性完成了針對授權頁面的重定向和Access
Token的請求和接收。除此之外,為了讓浏覽器能夠在第一次認證之後能夠自動地發送Access
Token,我們利用AuthenticateAttribute将Access
Token寫入了Cookie之中,這與Forms認證比較類似。不過就安全的角度來講,利用Cookie攜帶安全令牌會引起一種被稱為“跨站請求僞造(CSRF:Cross-Site
Request Forgery)”的安全問題,是以通過HTTP報頭來作為安全令牌的載體是更安全的做法。
如下所示的代碼片斷展現了整個AuthenticateAttribute特性的定義,我們可以看到它同時實作了IAuthenticationFilter和IActionFilter。字元串常量CookieName表示攜帶Access
Token的Cookie名稱,隻讀屬性CaptureTokenUri表示授權伺服器發送Access
Token采用的重定向位址,它指向一個我們由我們設計的Web頁面,該頁面在接受到Access
Token之後會自動向目标資源所在的位址發送一個請求,該請求位址以查詢字元串的形式攜帶此Access
Token。(之是以我們需要利用一個Web頁面在用戶端(浏覽器)接收并重發Access Token,是因為授權伺服器将傳回的Access
Token至于重定向URI的Hash(#)部分,是以在服務端是擷取不到的,隻能在用戶端來收集。這個Web頁面的目的在在于在用戶端擷取的Access Token并發送到服務端。)
在實作的ChallengeAsync方法(該方法在認證過程中向用戶端發送“質詢”響應)中,我們利用自定義的擴充方法TryGetAccessToken試着從目前請求中擷取攜帶的Access
Token。如果這樣的Access
Token不存在,我們通過為HttpAuthenticationChallengeContext的Result屬性設定一個RedirectResult對象實作針對Windows
Live
Connect授權頁面的重定向,相關的參數(respone-type、redirect_uri、client_id和scope)以查詢字元串的形式提供。
值得一提的作為重定向位址的參數redirect_uri,我們會将目前請求的位址作為查詢字元串(名稱為“requestUri”)附加到CaptureTokenUri上得到的URI作為該參數的值,目前請求的位址正式Web頁面發送Access
Token的目标位址。
另一個實作的ExecuteActionFilterAsync方法複雜将Access
Token寫入響應Cookie之中,具體的操作實作在我們自定義的擴充方法SetAccessToken中。下面的代碼片斷給出了兩個擴充方法SetAccessToken和TryGetAccessToken的定義。
在我們示範的執行個體中,應用在DemoController類型上的AuthenticateAttribute特性的CaptureTokenUri屬性(“https://www.artech.com/webapi/account/capturetoken”)指向定義在AccountController這麼一個Controller(ASP.NET
MVC的Controller,不是ASP.NET Web
API的HttpController)的Action方法CaptureToken,具體定義如下所示。
由于AuthenticateAttribute在調用Windows Live Connect的API擷取Access
Token所指定的重定向位址具有一個名為“requestUri”的查詢字元串,其值正好是調用Web
API的位址,該位址會自動綁定到Action方法CaptureToken的requestUri參數上。如果上面的代碼片斷所示,該方法會将該位址以ViewBag的形式傳遞到呈現的View之中。
上面的代碼片斷代表Action方法CaptureToken對應View的定義。在該View中,我們從目前位址的Hash(#)部分得到Access
Token,并将其作為查詢字元串附加到從ViewBag中得到的資源通路位址上,并通過設定location的href屬性的方式攜帶Access
Token對Web API再次發起調用。
<a href="http://www.cnblogs.com/artech/p/oauth-01.html">談談基于OAuth 2.0的第三方認證 [上篇]</a>
<a href="http://www.cnblogs.com/artech/p/oauth-02.html">談談基于OAuth 2.0的第三方認證 [中篇]</a>
<a href="http://www.cnblogs.com/artech/p/oauth-03.html">談談基于OAuth 2.0的第三方認證 [下篇]</a>
作者:蔣金楠
微信公衆賬号:大内老A
如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識别二維碼)關注個人公衆号(原來公衆帳号蔣金楠的自媒體将會停用)。
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。
<a href="http://www.cnblogs.com/artech/p/oauth-02.html" target="_blank">原文連結</a>