http://www.cnblogs.com/dudu/p/4569857.htmlhtml
OAuth真是一個複雜的東東,即便你把OAuth規範滾瓜爛熟,在具體實現時也會無從下手。所以,Microsoft.Owin.Security.OAuth應運而生(它的實現代碼在Katana項目中),幫助開發者偷了很多工,減了很多料。api
這篇博文試圖經過一個簡單的示例分享一下如何基於Microsoft.Owin.Security.OAuth,使用Client Credentials Grant受權方式給客戶端發放access token。app
Client Credentials Grant的受權方式就是隻驗證客戶端(Client),不驗證用戶(Resource Owner),只要客戶端經過驗證就發access token。舉一個對應的應用場景例子,好比咱們想提供一個「獲取網站首頁最新博文列表」的WebAPI給iOS App調用。因爲這個數據與用戶無關,因此不涉及用戶登陸與受權,不須要Resource Owner的參與。但咱們不想任何人均可以調用這個WebAPI,因此要對客戶端進行驗證,而使用OAuth中的 Client Credentials Grant 受權方式能夠很好地解決這個問題。ide
具體實現方式以下:測試
1)用Visual Studio 2013/2015建立一個Web API項目,VS會生成一堆OAuth相關代碼。網站
2)打開Startup.Auth.cs ,精簡一下代碼,咱們只須要實現以Client Credentials Grant受權方式拿到token,其它無關代碼所有清除,最終剩下以下代碼:ui
public partial class Startup { public void ConfigureAuth(IAppBuilder app) { var OAuthOptions = new OAuthAuthorizationServerOptions { TokenEndpointPath = new PathString("/token"), Provider = new CNBlogsAuthorizationServerProvider(), AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), AllowInsecureHttp = true }; app.UseOAuthBearerTokens(OAuthOptions); } }
3)建立一個新的類 CNBlogsAuthorizationServerProvider,並繼承自 OAuthAuthorizationServerProvider,重載 OAuthAuthorizationServerProvider() 與 GrantClientCredentials() 這兩個方法。代碼以下:spa
public class CNBlogsAuthorizationServerProvider : OAuthAuthorizationServerProvider { public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { string clientId; string clientSecret; context.TryGetFormCredentials(out clientId, out clientSecret); if (clientId == "1234" && clientSecret == "5678") { context.Validated(clientId); } return base.ValidateClientAuthentication(context); } public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context) { var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType); oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, "iOS App")); var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties()); context.Validated(ticket); return base.GrantClientCredentials(context); } }
在 ValidateClientAuthentication() 方法中獲取客戶端的 client_id 與 client_secret 進行驗證。code
在 GrantClientCredentials() 方法中對客戶端進行受權,授了權就能發 access token 。orm
這樣,OAuth的服務端代碼就完成了。這麼簡單?是的,就這麼簡單,由於有了Microsoft.Owin.Security.OAuth。
4)而後寫客戶端調用代碼測試一下:
public class OAuthClientTest { private HttpClient _httpClient; public OAuthClientTest() { _httpClient = new HttpClient(); _httpClient.BaseAddress = new Uri("http://openapi.cnblogs.com"); } [Fact] public void Get_Accesss_Token_By_Client_Credentials_Grant() { var parameters = new Dictionary<string, string>(); parameters.Add("client_id", "1234"); parameters.Add("client_secret", "5678"); parameters.Add("grant_type", "client_credentials"); Console.WriteLine(_httpClient.PostAsync("/token", new FormUrlEncodedContent(parameters)) .Result.Content.ReadAsStringAsync().Result); } }
運行結果以下:
{"access_token":"8PqaWilv_SJT7vRXambP7Mebyaf3KO1GXYHsqA-oPMOQF6xk1YpluczOZGo-WwATU5YmGb0wSR0cUQMC8RSZfwO8nwom7yG11FIANhy2PNiqTg2CYdJF0sf0ggFs6it_i3mc_m1iEFCK2dLBPDJXPI24wngCPR0wP_zugZvyKv314BM0PQmnnwg3kLXR1DISKRbs5-i59VCtFSZgkM7A0w","token_type":"bearer","expires_in":1209599}
搞定!
【更新】
建議使用Basic Authentication傳遞clientId與clientSecret,服務端CNBlogsAuthorizationServerProvider中的TryGetFormCredentials()改成TryGetBasicCredentials(),客戶端的調用代碼以下:
public class OAuthClientTest { private HttpClient _httpClient; public OAuthClientTest() { _httpClient = new HttpClient(); _httpClient.BaseAddress = new Uri("http://openapi.cnblogs.com"); } [Fact] public void Get_Accesss_Token_By_Client_Credentials_Grant() { var clientId = "1234"; var clientSecret = "5678"; _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(clientId + ":" + clientSecret))); var parameters = new Dictionary<string, string>(); parameters.Add("grant_type", "client_credentials"); Console.WriteLine(_httpClient.PostAsync("/token", new FormUrlEncodedContent(parameters)) .Result.Content.ReadAsStringAsync().Result); } }