DotNetOpenAuth Part 1 : Authorization 驗證服務實現及關鍵源碼解析

DotNetOpenAuth 是 .Net 環境下OAuth 開源實現框架。基於此,能夠方便的實現 OAuth 驗證(Authorization)服務、資源(Resource)服務。針對 DotNetOpenAuth,近期打算整理出三篇隨筆:html

  DotNetOpenAuth Part 1 : OAuth2 Authorization 驗證服務實現及關鍵源碼解析服務器

  DotNetOpenAuth Part 2 : OAuth2 Resource 資源服務實現及關鍵源碼解析框架

  DotNetOpenAuth Part 3 : OAuth2 Client 訪問實現幾關鍵源碼解析async

 

本篇是這一系列的 Part 1。ide

OAuth Authorization 服務負責爲用戶下發 Access Token,然後用戶用這一 Token 去請求資源和邏輯訪問。Client 端發送來附帶 ClientId 和 ClientSecret 的 request,Authorization 端驗證請求的合法性,生成 Access Token 並下發,這就是OAuth 驗證服務的主要職責。ui

【實現層面】this

基於 DotNetOpenAuth 開發 Authorization 服務的主要工做是實現 IAuthorizationServerHost 接口,而其中關鍵要實現的方法有兩個,它們分別是 GetClient 和 CreateAccessToken。spa

 1 IClientDescription GetClient(string clientIdentifier); .net

由 Client 端發送來的標示 clientIdentifier 獲取該 Client 在驗證服務端的詳細信息,以備作 ClientSecret 比對驗證。這裏 ClientDescription 的來源能夠是驗證服務端DB,也能夠是其餘可提供該數據的外部服務。code

 1 AccessTokenResult CreateAccessToken(IAccessTokenRequest accessTokenRequestMessage); 

 基於策略,生成 AccessToken,並返回給請求驗證的 Client。

 

方法實現示意

GetClient,

 1 public IClientDescription GetClient(string clientIdentifier)
 2 {
 3     if (string.Equals(clientIdentifier, "iSun", StringComparison.CurrentCulture))
 4     {
 5         var client = new Client()       // Just initiate a Client instance, and in production it comes from DB or other service. 
 6         {
 7             Name = "iSun",
 8             ClientSecret = "1",
 9             ClientTypeValue = 1
10         };
11 
12         return client;
13     }
14 
15     throw new ArgumentOutOfRangeException("clientIdentifier");
16 }

CreateAccessToken,

 1 public AccessTokenResult CreateAccessToken(IAccessTokenRequest accessTokenRequestMessage)
 2 {
 3     var accessToken = new AuthorizationServerAccessToken();
 4         
 5     accessToken.Lifetime = TimeSpan.FromMinutes(2);
 6     accessToken.ResourceServerEncryptionKey = ... ...
 7     accessToken.AccessTokenSigningKey = ... ...
 8 
 9     var result = new AccessTokenResult(accessToken);
10     return result;
11 }

實現了 IAuthorizationServerHost 接口下的兩個關鍵方法,下面要作的僅僅是使用該 AuthorizationServerHost 實例初始化 AuthorizationServer 類,並調用其 HandleTokenRequestAsync 方法。

1 private readonly AuthorizationServer authorizationServer = new AuthorizationServer(new iSunAuthorizationServerHost(AuthService.Configuration));
2 
3 public async Task<ActionResult> Token()
4 {
5     var response = await authorizationServer.HandleTokenRequestAsync(Request);
6     return response.AsActionResult();
7 }

 

【原理層面】

實現層面的介紹就是這些,是否是很簡單?但僅知道這些顯然不夠,你始終仍是不明 ... 但覺厲。DotNetOpenAuth Authorization 框架如何作到僅這兩個方法就實現了驗證服務呢?好在 DotNetOpenAuth 是開源項目,咱們研究一下源碼就會豁然開朗。先上一張 Authorization 內部調用的示意圖(點擊打開大圖)。

如圖所示,調用始自 AuthorizationServer.HandleTokenRequestAsync,後依次經步驟1 - 9,終於 AuthorizationServerHost.CreateAccessToken 調用。其中步驟七、八、9是整個 Token 下發過程當中的關鍵方法調用。Step 7 GetClient 獲取 request 端的詳細信息,以後Step 8 IsValidClientSecret 驗證 ClientSecret 合法性,若驗證經過則Step 9 CreateAccessToken 並下發予請求的 Client 端。邏輯示意圖以下(點擊打開大圖)。

關鍵步驟七、八、9源碼片斷以下:

調用 GetClient,並進行 ClientSecret Validation(DotNetOpenAuth.OAuth2.ChannelElements.ClientAuthenticationModule 中 TryAuthenticateClientBySecret 方法)。

 1 protected static ClientAuthenticationResult TryAuthenticateClientBySecret(IAuthorizationServerHost authorizationServerHost, 
 2     string clientIdentifier, string clientSecret) {
 3     Requires.NotNull(authorizationServerHost, "authorizationServerHost");
 4 
 5     if (!string.IsNullOrEmpty(clientIdentifier)) {
 6         var client = authorizationServerHost.GetClient(clientIdentifier);       // Step 7: GetClient returns IClientDescription
 7         if (client != null) {
 8             if (!string.IsNullOrEmpty(clientSecret)) {
 9                 if (client.IsValidClientSecret(clientSecret)) {                 // Step 8: Validate ClientSecret
10                     return ClientAuthenticationResult.ClientAuthenticated;
11                 } else { // invalid client secret
12                     return ClientAuthenticationResult.ClientAuthenticationRejected;
13                 }
14             }
15 }
16 }
17 }

ClientDescription.IsValidClientSecret 方法(DotNetOpenAuth.OAuth2.ClientDescription 中 IsValidClientSecret 方法)。

1 public virtual bool IsValidClientSecret(string secret) {
2     Requires.NotNullOrEmpty(secret, "secret");
3 
4     return MessagingUtilities.EqualsConstantTime(secret, this.secret);
5 }

調用 CreateAccessToken 代碼片斷,若 Client 驗證未經過,則返回 InvalidRequest(line 23)(DotNetOpenAuth.OAuth2.AuthorizationServer 中方法 HandleTokenRequestAsync)。

 1 AccessTokenRequestBase requestMessage = await this.Channel.TryReadFromRequestAsync<AccessTokenRequestBase>(request, cancellationToken);
 2 if (requestMessage != null) {
 3     // Step 9: Call AuthorizationServerHost.CreateAccessToken to generate Token
 4     var accessTokenResult = this.AuthorizationServerServices.CreateAccessToken(requestMessage);     
 5     ErrorUtilities.VerifyHost(accessTokenResult != null, "IAuthorizationServerHost.CreateAccessToken must not return null.");
 6 
 7     IAccessTokenRequestInternal accessRequestInternal = requestMessage;
 8     accessRequestInternal.AccessTokenResult = accessTokenResult;
 9 
10     var successResponseMessage = this.PrepareAccessTokenResponse(requestMessage, accessTokenResult.AllowRefreshToken);
11     successResponseMessage.Lifetime = accessTokenResult.AccessToken.Lifetime;
12     ......
13     responseMessage = successResponseMessage;
14 } else {
15     // Validation failed, return error with InvalidRequest
16     responseMessage = new AccessTokenFailedResponse() { Error = Protocol.AccessTokenRequestErrorCodes.InvalidRequest };
17 }

 

【小結】

應用 DotNetOpenAuth 框架開發 OAuth 驗證服務比較容易,但若是不瞭解其實現原理,開發過程當中難免心虛,遇到問題也不能快速解決。因此,不只知其然,知其因此然仍是很重要的。(此篇所示代碼多爲示意用途,若想下載Demo,參考資料2處有詳細代碼,我在本篇就不貼出了。須要 DotNetOpenAuth 源碼和 Sample 的,可前往官網 http://www.dotnetopenauth.net/


參考資料:

一、[OAuth]基於DotNetOpenAuth實現Client Credentials Grant  http://www.cnblogs.com/dudu/p/oauth-dotnetopenauth-client-credentials-grant.html

二、DotNetOpenAuth實踐之搭建驗證服務器  http://www.cnblogs.com/idefav2010/p/DotNetOpenAuth.html

三、http://www.dotnetopenauth.net/

相關文章
相關標籤/搜索