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簽名製作,下篇我們一起來看看如何製作一個認證伺服器可以使用的簽名證書