博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ASP.NET Web API与Owin OAuth:调用与用户相关的Web API
阅读量:7008 次
发布时间:2019-06-28

本文共 5196 字,大约阅读时间需要 17 分钟。

在前一篇中,我们通过以 OAuth 的 Client Credential Grant 授权方式(只验证调用客户端,不验证登录用户)拿到的 Access Token ,成功调用了与用户无关的 Web API。

在这篇博文中,我们将以 OAuth 的  的授权方式( grant_type=password )获取 Access Token,并以这个 Token 调用与用户相关的 Web API。

对应的应用场景是:为自家的网站开发手机 App(非第三方 App),只需用户在 App 上登录,无需用户对 App 所能访问的数据进行授权。

根据 OAuth ,客户端获取 Access Token 的请求方式如下:

POST /token HTTP/1.1Host: server.example.comAuthorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JWContent-Type: application/x-www-form-urlencodedgrant_type=password&username=johndoe&password=A3ddj3w

根据上面的请求方式,在 C# 中用 HttpClient 实现一个简单的客户端,代码如下:

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
GetAccessToken() { var clientId = "1234"; var clientSecret = "5678"; var parameters = new Dictionary
(); parameters.Add("grant_type", "password"); parameters.Add("username", "博客园团队"); 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
(); } else { Console.WriteLine(responseValue); return string.Empty; } }}

(注:与之前相比,这里的 client_id/client_secret 改为了 Basic Authorization,以更好的遵循 OAuth 规范)

在服务端,基于 Owin OAuth, 针对 Resource Owner Password Credentials Grant 的授权方式,只需重载 OAuthAuthorizationServerProvider.GrantResourceOwnerCredentials() 方法即可。代码如下:

public class CNBlogsAuthorizationServerProvider : OAuthAuthorizationServerProvider{    //...    public override async Task GrantResourceOwnerCredentials(        OAuthGrantResourceOwnerCredentialsContext context)    {        //调用后台的登录服务验证用户名与密码        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);    }}

完整的CNBlogsAuthorizationServerProvider实现代码如下(与之前相比,context.TryGetFormCredentials 改为了 context.TryGetBasicCredentials):

public 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)    {        //调用后台的登录服务验证用户名与密码        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);    }}
CNBlogsAuthorizationServerProvider

这样,运行客户端程序就可以拿到 Access Token 了。

接下来,我们拿着以这种方式获取的 Access Token,就可以调用与用户相关的 Web API 了。

在服务端我们通过一个简单的 Web API 测试一下,代码如下:

public class UsersController : ApiController{    [Authorize]    public string GetCurrent()    {        return User.Identity.Name;        //这里可以调用后台用户服务,获取用户相关数所,或者验证用户权限进行相应的操作    }}

然后,客户端用以 grant_type=password 方式拿到的 Access Token 调用这个Web API,客户端增加的代码如下:

[Fact]public async Task Call_WebAPI_By_Resource_Owner_Password_Credentials_Grant(){    var token = await GetAccessToken();    _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);    Console.WriteLine(await (await _httpClient.GetAsync("/api/users/current")).Content.ReadAsStringAsync());}

客户端运行结果如下:

"博客园团队"

调用成功!运行结果正是获取 Access Token 时所用的 username 。 

结合 ASP.NET 现有的安全机制,借助 OWIN 的威力,Microsoft.Owin.Security.OAuth 的确让开发基于 OAuth 的 Web API 变得更简单。

转载于:https://www.cnblogs.com/dudu/p/4578511.html

你可能感兴趣的文章
杭电ACM--2000ASCII码排序
查看>>
hdfs读写策略
查看>>
python 基础 8.4 re的 spilt() findall() finditer() 方法
查看>>
centos命令行变成了-bash-4.1$的解决办法
查看>>
今天有进步
查看>>
PYTHON 写入list并换行的方法
查看>>
反编译工具
查看>>
P1351 联合权值
查看>>
#1 add life to static pages && connect to MySQL
查看>>
Netty(二)
查看>>
jquery常用代码
查看>>
CF1140F - Extending Set of Points
查看>>
编译原理中LR(0)项目集规范族的构造
查看>>
python操作mongo脚本
查看>>
C++函数的升级下_5
查看>>
luci小记
查看>>
C#操作JSON字符串
查看>>
ROC-RK3308-CC固件编译工具——Docker 方式
查看>>
网页设计之路(1)
查看>>
AngularJs的UI组件ui-Bootstrap分享(十三)——Progressbar
查看>>