1. 程式人生 > 實用技巧 >DotNetOpenAuth實踐之搭建驗證伺服器

DotNetOpenAuth實踐之搭建驗證伺服器

DotNetOpenAuth是OAuth2的.net版本,利用DotNetOpenAuth我們可以輕鬆的搭建OAuth2驗證伺服器,不廢話,下面我們來一步步搭建驗證伺服器

本次搭建環境:

.net4.5.1 ,DotNetOpenAuth v5.0.0-alpha3,MVC5

一、環境搭建

  1、新建一個空的VS解決方案

  2、新增驗證伺服器專案,專案選擇MVC,不要自帶的身份驗證

  3、使用Nuget新增DotNetOpenAuth v5.0.0-alpha3

輸入DotNetOpenAuth 安裝DotNetOpenAuth v5.0.0-alpha3

新增完成後

二、編寫DotNetOpenAuth 驗證伺服器關鍵程式碼,實現功能

  1、新增AuthorizationServerConfiguration.cs

這裡的配置是為了新增方便管理,其實可以不用這個類

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Security.Cryptography.X509Certificates;
 5 using System.Web;
 6 
 7 namespace IdefavAuthorizationServer.Code
 8 {
 9     /// <summary>
10     /// 驗證伺服器配置
11     /// </summary>
12     public class AuthorizationServerConfiguration
13     {
14         /// <summary>
15         /// 建構函式
16         /// </summary>
17         public AuthorizationServerConfiguration()
18         {
19             TokenLifetime = TimeSpan.FromMinutes(5);
20         }
21 
22         /// <summary>
23         /// 簽名證書
24         /// </summary>
25         public X509Certificate2 SigningCertificate { get; set; }
26 
27         /// <summary>
28         /// 加密證書
29         /// </summary>
30         public X509Certificate2 EncryptionCertificate { get; set; }
31 
32         /// <summary>
33         /// Token有效時間
34         /// </summary>
35         public TimeSpan TokenLifetime { get; set; }
36     }
37 }

2、實現IClientDescription介面

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using DotNetOpenAuth.Messaging;
 6 using DotNetOpenAuth.OAuth2;
 7 
 8 namespace IdefavAuthorizationServer.Code
 9 {
10     public class Client : IClientDescription
11     {
12         /// <summary>
13         /// 客戶端名稱client_id
14         /// </summary>
15         public string Name { get; set; }
16 
17         /// <summary>
18         /// 客戶端型別
19         /// </summary>
20         public int ClientType { get; set; }
21 
22         /// <summary>
23         /// 回撥URL
24         /// </summary>
25         public string Callback { get; set; }
26 
27         public string ClientSecret { get; set; }
28 
29 
30         Uri IClientDescription.DefaultCallback
31         {
32             get { return string.IsNullOrEmpty(this.Callback) ? null : new Uri(this.Callback); }
33         }
34 
35 
36         ClientType IClientDescription.ClientType
37         {
38             get { return (ClientType)this.ClientType; }
39         }
40 
41 
42         bool IClientDescription.HasNonEmptySecret
43         {
44             get { return !string.IsNullOrEmpty(this.ClientSecret); }
45         }
46 
47 
48         bool IClientDescription.IsCallbackAllowed(Uri callback)
49         {
50             if (string.IsNullOrEmpty(this.Callback))
51             {
52                 // No callback rules have been set up for this client.
53                 return true;
54             }
55 
56             // In this sample, it's enough of a callback URL match if the scheme and host match.
57             // In a production app, it is advisable to require a match on the path as well.
58             Uri acceptableCallbackPattern = new Uri(this.Callback);
59             if (string.Equals(acceptableCallbackPattern.GetLeftPart(UriPartial.Authority), callback.GetLeftPart(UriPartial.Authority), StringComparison.Ordinal))
60             {
61                 return true;
62             }
63 
64             return false;
65         }
66 
67 
68         bool IClientDescription.IsValidClientSecret(string secret)
69         {
70             return MessagingUtilities.EqualsConstantTime(secret, this.ClientSecret);
71         }
72 
73 
74     }
75 }

3、實現IAuthorizationServerHost介面

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Security.Cryptography;
 5 using System.Web;
 6 using DotNetOpenAuth.Messaging.Bindings;
 7 using DotNetOpenAuth.OAuth2;
 8 using DotNetOpenAuth.OAuth2.ChannelElements;
 9 using DotNetOpenAuth.OAuth2.Messages;
10 
11 namespace IdefavAuthorizationServer.Code
12 {
13     public class IdefavAuthorizationServerHost : IAuthorizationServerHost
14     {
15         /// <summary>
16         /// 配置
17         /// </summary>
18         private readonly AuthorizationServerConfiguration _configuration;
19 
20         /// <summary>
21         /// 建構函式
22         /// </summary>
23         /// <param name="config"></param>
24         public IdefavAuthorizationServerHost(AuthorizationServerConfiguration config)
25         {
26             if (config != null)
27                 _configuration = config;
28         }
29 
30         /// <summary>
31         /// Token建立
32         /// </summary>
33         /// <param name="accessTokenRequestMessage"></param>
34         /// <returns></returns>
35         public AccessTokenResult CreateAccessToken(IAccessTokenRequest accessTokenRequestMessage)
36         {
37             var accessToken = new AuthorizationServerAccessToken();
38             accessToken.Lifetime = _configuration.TokenLifetime;//設定Token的有效時間
39 
40             // 設定加密公鑰
41             accessToken.ResourceServerEncryptionKey =
42                 (RSACryptoServiceProvider)_configuration.EncryptionCertificate.PublicKey.Key;
43             // 設定簽名私鑰
44             accessToken.AccessTokenSigningKey = (RSACryptoServiceProvider)_configuration.SigningCertificate.PrivateKey;
45 
46             var result = new AccessTokenResult(accessToken);
47             return result;
48         }
49 
50         public IClientDescription GetClient(string clientIdentifier)
51         {
52             // 這裡需要去驗證客戶端傳送過來的client_id
53             if (string.Equals(clientIdentifier, "idefav", StringComparison.CurrentCulture))// 這裡為了簡明起見沒有使用資料庫
54             {
55                 var client=new Client
56                 {
57                     Name = "idefav",
58                     ClientSecret = "1",
59                     ClientType = 1
60                 };
61                 return client;
62             }
63             throw new ArgumentOutOfRangeException("clientIdentifier");
64         }
65 
66         public bool IsAuthorizationValid(IAuthorizationDescription authorization)
67         {
68             return true;
69         }
70 
71         public AutomatedUserAuthorizationCheckResponse CheckAuthorizeResourceOwnerCredentialGrant(string userName, string password,
72             IAccessTokenRequest accessRequest)
73         {
74             throw new NotImplementedException();
75         }
76 
77         public AutomatedAuthorizationCheckResponse CheckAuthorizeClientCredentialsGrant(IAccessTokenRequest accessRequest)
78         {
79             AutomatedUserAuthorizationCheckResponse response = new AutomatedUserAuthorizationCheckResponse(accessRequest, true, "test");
80             return response;
81         }
82 
83         public ICryptoKeyStore CryptoKeyStore { get; }
84         public INonceStore NonceStore { get; }
85 
86        
87     }
88 }

4、實現OAuthController

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Threading.Tasks;
 5 using System.Web;
 6 using System.Web.Mvc;
 7 using DotNetOpenAuth.Messaging;
 8 using DotNetOpenAuth.OAuth2;
 9 using IdefavAuthorizationServer.Code;
10 
11 namespace IdefavAuthorizationServer.Controllers
12 {
13     public class OAuthController : Controller
14     {
15         private readonly AuthorizationServer authorizationServer =
16            new AuthorizationServer(new IdefavAuthorizationServerHost(Common.Configuration));
17 
18         public async Task<ActionResult> Token()
19         {
20             var response = await authorizationServer.HandleTokenRequestAsync(Request);
21             return response.AsActionResult();
22         }
23     }
24 }

5、初始化AuthorizationServerConfiguration

這裡採用Windows簽名證書

放到專案中

製作證書事注意:要加上-a sha1-sky exchange

到此,基本程式碼就寫完了,現在說說要注意的地方,OAuth2預設設定的請求是要求SSL的也就是必須是https//localhost:1111/OAuth/Token,然後我們現在不需要使用SSL加密請求,更改一下WebConfig檔案

在WebConfig裡面設定成如圖中那樣,就可以不用https訪問了

6、我們F5執行專案

使用Post工具傳送Post請求訪問http://localhost:53022/OAuth/token

Body引數:

1 client_id:idefav
2 client_secret:1
3 grant_type:client_credentials

請求結果:

這樣我們就拿到了access_token,通過這個access_token我們就可以訪問資源伺服器了

更新:

OAuthController程式碼新增內容型別

 1 using System.Collections.Generic;
 2 using System.Linq;
 3 using System.Threading.Tasks;
 4 using System.Web;
 5 using System.Web.Mvc;
 6 using System.Web.Script.Services;
 7 using DotNetOpenAuth.Messaging;
 8 using DotNetOpenAuth.OAuth2;
 9 using IdefavAuthorizationServer.Code;
10 
11 namespace IdefavAuthorizationServer.Controllers
12 {
13     public class OAuthController : Controller
14     {
15         private readonly AuthorizationServer authorizationServer =
16            new AuthorizationServer(new IdefavAuthorizationServerHost(Common.Configuration));
17         
18         public async Task<ActionResult> Token()
19         {
20             var response = await authorizationServer.HandleTokenRequestAsync(Request);
21             Response.ContentType = response.Content.Headers.ContentType.ToString();
22             return response.AsActionResult();
23         }
24     }
25 }

鑑於有人不知道Windows簽名製作,下篇我們一起來看看如何製作一個認證伺服器可以使用的簽名證書