ASP.NET Web API与Owin OAuth:调用与用户相关的Web API
在前一篇博文中,我们通过以 OAuth 的 Client Credential Grant 授权方式(只验证调用客户端,不验证登录用户)拿到的 Access Token ,成功调用了与用户无关的 Web API。
在这篇博文中,我们将以 OAuth 的 Resource Owner Password Credentials Grant 的授权方式( grant_type=password )获取 Access Token,并以这个 Token 调用与用户相关的 Web API。
对应的应用场景是:为自家的网站开发手机 App(非第三方 App),只需用户在 App 上登录,无需用户对 App 所能访问的数据进行授权。
根据 OAuth 规范,客户端获取 Access Token 的请求方式如下:
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
根据上面的请求方式,在 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<string> GetAccessToken()
{
var clientId = "";
var clientSecret = ""; var parameters = new Dictionary<string, string>();
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<string>();
}
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 == ""
&& clientSecret == "")
{
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 变得更简单。
ASP.NET Web API与Owin OAuth:调用与用户相关的Web API的更多相关文章
- ASP.NET Web API与Owin OAuth:调用与用户相关的Web API(非第三方登录)
授权完成添加属性 ClaimsIdentity oAuthIdentity = await CreateAsync(user/*userManager*/, OAuthDefaults.Authent ...
- ASP.NET Web API与Owin OAuth:使用Access Toke调用受保护的API
在前一篇博文中,我们使用OAuth的Client Credential Grant授权方式,在服务端通过CNBlogsAuthorizationServerProvider(Authorization ...
- 在ASP.NET Web API 2中使用Owin OAuth 刷新令牌(示例代码)
在上篇文章介绍了Web Api中使用令牌进行授权的后端实现方法,基于WebApi2和OWIN OAuth实现了获取access token,使用token访问需授权的资源信息.本文将介绍在Web Ap ...
- 在WebApi中基于Owin OAuth使用授权发放Token
如何基于Microsoft.Owin.Security.OAuth,使用Client Credentials Grant授权方式给客户端发放access token? Client Credentia ...
- IdentityServer4 ASP.NET Core的OpenID Connect OAuth 2.0框架学习保护API
IdentityServer4 ASP.NET Core的OpenID Connect OAuth 2.0框架学习之保护API. 使用IdentityServer4 来实现使用客户端凭据保护ASP.N ...
- [ASP.NET] 结合Web API在OWIN下实现OAuth
OAuth(Open Authorization) 为用户资源的授权提供了一个安全的.开放而又简易的标准.与以往的授权方式不同之处是OAuth的授权不会使第三方触及到用户的帐号信息(如用户名与密码), ...
- Web API在OWIN下实现OAuth
OAuth(Open Authorization) 为用户资源的授权提供了一个安全的.开放而又简易的标准.与以往的授权方式不同之处是OAuth的授权不会使第三方触及到用户的帐号信息(如用户名与密码), ...
- 为IIS Host ASP.NET Web Api添加Owin Middleware
将OWIN App部署在IIS上 要想将Owin App部署在IIS上,只添加Package:Microsoft.OWIN.Host.SystemWeb包即可.它提供了所有Owin配置,Middlew ...
- 在ASP dot Net Core MVC中用Controllers调用你的Asp dotnet Core Web API 实现CRUD到远程数据库中,构建你的分布式应用(附Git地址)
本文所有的东西都是在dot Net Core 1.1环境+VS2017保证测试通过. 本文接着上次文章接着写的,不了解上篇文章的可能看着有点吃力.我尽量让大家都能看懂.这是上篇文章的连接http:// ...
随机推荐
- 操作系统篇-调用门与特权级(CPL、DPL和RPL)
|| 版权声明:本文为博主原创文章,未经博主允许不得转载. 一.前言 在前两篇文章(<操作系统篇-浅谈实模式与保护模式>和<操作系统篇-分段机制与GDT|LDT>)中,我们提到 ...
- jsp前端实现分页代码
前端需要订一page类包装,其参数为 private Integer pageSize=10; //每页记录条数=10 private Integer totalCount; //总记录条数 priv ...
- .Net多线程编程—预备知识
1 基本概念 共享内存的多核架构:一个单独的封装包内封装了多个互相连接的未处理器,且所有内核都可以访问主内存.共享内存的多核系统的一些微架构,例如内核暂停功能,超频. 内核暂停功能:当使用内核不多的时 ...
- 浅谈Slick(2)- Slick101:第一个动手尝试的项目
看完Slick官方网站上关于Slick3.1.1技术文档后决定开始动手建一个项目来尝试一下Slick功能的具体使用方法.我把这个过程中的一些了解和想法记录下来和大家一起分享.首先我用IntelliJ- ...
- xss和sql注入原理学习
8.4 Web跨站脚本攻击 8.4.1 跨站脚本攻击的原理(1) 跨站脚本在英文中称为Cross-Site Scripting,缩写为CSS.但是,由于层叠样式表 (Cascading Style ...
- DBobjectsCompareScript(数据库对象比较).sql
use master goIF EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N'[func_CompareDBobjectsReColu ...
- Prometheus 系统监控方案 一
最近一直在折腾时序类型的数据库,经过一段时间项目应用,觉得十分不错.而Prometheus又是刚刚推出不久的开源方案,中文资料较少,所以打算写一系列应用的实践过程分享一下. Prometheus 是什 ...
- JavaMail发送邮件
发送邮件包含的内容有: from字段 --用于指明发件人 to字段 --用于指明收件人 subject字段 --用于说明邮件主题 cc字段 -- 抄送,将邮件发送给收件人的同时抄 ...
- XSS 前端防火墙 —— 天衣无缝的防护
上一篇讲解了钩子程序的攻防实战,并实现了一套对框架页的监控方案,将防护作用到所有子页面. 到目前为止,我们防护的深度已经差不多,但广度还有所欠缺. 例如,我们的属性钩子只考虑了 setAttribut ...
- xamarin绑定原生库的一些坑
最近一个项目涉及到较多的第三方库的绑定技术,中间遇到了几个坑,记录下来与大家分享 绑定Jar库 monoandroid对原生库的调用都通过Android.Runtime.JNIEnv进行调入(http ...