Reference page:
http://www.yuanjiaocheng.net/webapi/web-api-route.html
http://www.yuanjiaocheng.net/webapi/parameter-binding.html
http://www.yuanjiaocheng.net/webapi/action-method-returntype.html
http://www.yuanjiaocheng.net/webapi/web-api-reqresq-format.html
http://www.yuanjiaocheng.net/webapi/media-formatter.html
In the previous article Bowen In OAuth, we successfully invoked the user-independent Web API by using Acess Token authorized by Client Credential Grant (only validating the calling client, not the logged-in user).
In this blog post, we will use OAuth's uuuuuuuuuuuu Resource Owner Password Credentials Grant Access Token is acquired by grant_type=password, and the user-related Web API is invoked by this Token.
The corresponding application scenario is to develop mobile App (non-third-party App) for its own website, which only requires users to log on to App without authorizing the data that App can access.
According to OAuth Standard Client requests for Access Token are as follows:
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=password&username=johndoe&password=A3ddj3w
According to the above request mode, a simple client is implemented in C # with HttpClient. The code is as follows:
public class OAuthClientTest { private HttpClient _httpClient; public OAuthClientTest() { _httpClient = new HttpClient(); _httpClient.BaseAddress = new Uri("http://openapi.cnblogs.com"); } [Fact] public async Task Get_Accesss_Token_By_Resource_Owner_Password_Credentials_Grant() { Console.WriteLine(await GetAccessToken()); } private async Task<string> GetAccessToken() { var clientId = "1234"; var clientSecret = "5678"; var parameters = new Dictionary<string, string>(); parameters.Add("grant_type", "password"); parameters.Add("username", "Blog Garden Team"); parameters.Add("password", "cnblogs.com"); _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes(clientId + ":" + clientSecret)) ); var response = await _httpClient.PostAsync("/token", new FormUrlEncodedContent(parameters)); var responseValue = await response.Content.ReadAsStringAsync(); if (response.StatusCode == System.Net.HttpStatusCode.OK) { return JObject.Parse(responseValue)["access_token"].Value<string>(); } else { Console.WriteLine(responseValue); return string.Empty; } } }
(Note: The client_id/client_secret here is changed to Basic Authorization to better comply with the OAuth specification than before)
On the server side, based on Owin OAuth, for the authorization mode of Resource Owner Password Credentials Grant, it only needs to overload the OAuth Authorization Server Provider. Grant Resource Owner Credentials () method. The code is as follows:
public class CNBlogsAuthorizationServerProvider : OAuthAuthorizationServerProvider { //... public override async Task GrantResourceOwnerCredentials( OAuthGrantResourceOwnerCredentialsContext context) { //Call the background login service to verify the username and password var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType); oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, context.UserName)); var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties()); context.Validated(ticket); await base.GrantResourceOwnerCredentials(context); } }
The complete CNBlogs Authorization Server Provider implementation code is as follows (context.TryGetFormCredentials instead of context. TryGetBasic Credentials):
CNBlogsAuthorizationServerProviderpublic class CNBlogsAuthorizationServerProvider : OAuthAuthorizationServerProvider { public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { string clientId; string clientSecret; context.TryGetBasicCredentials(out clientId, out clientSecret); if (clientId == "1234" && clientSecret == "5678") { context.Validated(clientId); } await base.ValidateClientAuthentication(context); } public override async Task GrantClientCredentials(OAuthGrantClientCredentialsContext context) { var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType); var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties()); context.Validated(ticket); await base.GrantClientCredentials(context); } public override async Task GrantResourceOwnerCredentials( OAuthGrantResourceOwnerCredentialsContext context) { //Call the background login service to verify the username and password var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType); oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, context.UserName)); var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties()); context.Validated(ticket); await base.GrantResourceOwnerCredentials(context); } }