[OAuth]基于DotNetOpenAuth实现Client Credentials Grant

 

Client Credentials Grant是指直接由Client向Authorization Server请求access token,无需用户(Resource Owner)的授权。比如我们提供OpenAPI让大家可以获取园子首页最新随笔,只需验证一下Client是否有权限调用该API,不需要用户的授权。而如果Client需要进行发布博客的操作,就需要用户的授权,这时就要采用Authorization Code Grant

DotNetOpenAuth是当前做得做好的基于.NET的OAuth开源实现,项目网址:https://github.com/DotNetOpenAuth

Client Credentials Grant的流程图如下(图片1来源图片2来源):

一、Client向Authorization Server请求access token

主要操作如下:

1. 由client_id和client_secret构建出credentials。

2. 将credentials以http basic authentication的方式发送给Authorization Server。

3. 从Authorization Server的响应中提取access token

Client的实现代码如下:

public async Task<ActionResult> SiteHome()
{
var client_id = "m.cnblogs.com";
var client_secret = "20140213";
var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(client_id + ":" + client_secret)); var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentials);
var httpContent = new FormUrlEncodedContent(new
Dictionary<string, string>
{
{"grant_type", "client_credentials"}
}); var response = await httpClient.PostAsync("https://authserver.open.cnblogs.com/oauth/token", httpContent); var responseContent = await response.Content.ReadAsStringAsync();
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var accessToken = JObject.Parse(responseContent)["access_token"].ToString();
return Content("AccessToken: " + accessToken);
}
else
{
return Content(responseContent);
}
}

二、Authorization Server验证Client,发放access token

主要操作如下:

1. Authorization Server通过IAuthorizationServerHost.GetClient()获取当前Client。

2. Authorization Server通过IClientDescription.IsValidClientSecret()验证当前Client。

3. 验证通过后,将access token包含在响应中发送给Client。

主要实现代码如下(基于ASP.NET MVC):

1. Authorization Server中Client实体类的实现代码(关键代码是IsValidClientSecret()的实现):

    public class Client : IClientDescription
{
public string Id { get; set; } public string Secret { get; set; } public Uri DefaultCallback
{
get { throw new NotImplementedException(); }
} private ClientType _clientType;
public ClientType ClientType
{
get { return _clientType; }
set { _clientType = value; }
} public bool HasNonEmptySecret
{
get { throw new NotImplementedException(); }
} public bool IsCallbackAllowed(Uri callback)
{
throw new NotImplementedException();
} public bool IsValidClientSecret(string secret)
{
return this.Secret == secret;
}
}

AuthorizationServerHost的代码(关键代码是GetClient()与CreateAccessToken()的实现):

public class AuthorizationServerHost : IAuthorizationServerHost
{
public static readonly ICryptoKeyStore HardCodedCryptoKeyStore = new HardCodedKeyCryptoKeyStore("..."); public IClientDescription GetClient(string clientIdentifier)
{
return ServiceLocator.GetService<IClientService>().GetClient(clientIdentifier);
} public AccessTokenResult CreateAccessToken(IAccessTokenRequest accessTokenRequestMessage)
{
var accessToken = new AuthorizationServerAccessToken
{
Lifetime = TimeSpan.FromHours(10),
SymmetricKeyStore = this.CryptoKeyStore,
};
var result = new AccessTokenResult(accessToken);
return result;
} public AutomatedAuthorizationCheckResponse CheckAuthorizeClientCredentialsGrant(IAccessTokenRequest accessRequest)
{
//...
} public AutomatedUserAuthorizationCheckResponse CheckAuthorizeResourceOwnerCredentialGrant
(string userName, string password, IAccessTokenRequest accessRequest)
{
//...
} public DotNetOpenAuth.Messaging.Bindings.ICryptoKeyStore CryptoKeyStore
{
get { return HardCodedCryptoKeyStore; }
} public bool IsAuthorizationValid(IAuthorizationDescription authorization)
{
return true;
} public INonceStore NonceStore
{
get { return null; }
}
}

三、Client通过access token调用Resource Server上的API

主要实现代码如下:

public async Task<ActionResult> HomePosts(string blogApp)
{
//获取access token的代码见第1部分
//...
var accessToken = JObject.Parse(responseContent)["access_token"].ToString();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
response = await httpClient.GetAsync("https://api.open.cnblogs.com/blog/posts/sitehome");
return Content(await response.Content.ReadAsStringAsync());
}

四、Resource Server验证Client的access token,响应Client的API调用请求

主要实现代码如下(基于ASP.NET Web API):

1. 通过MessageHandler统一验证access token

public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new BearerTokenHandler());
}
}

2. BearerTokenHandler的实现代码(来自DotNetOpenAuth的示例代码):

public class BearerTokenHandler : DelegatingHandler
{
protected override async System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
if (request.Headers.Authorization != null && request.Headers.Authorization.Scheme == "Bearer")
{
var resourceServer = new DotNetOpenAuth.OAuth2.ResourceServer
(new StandardAccessTokenAnalyzer
(AuthorizationServerHost.HardCodedCryptoKeyStore)); var principal = await resourceServer.GetPrincipalAsync(request, cancellationToken);
HttpContext.Current.User = principal;
Thread.CurrentPrincipal = principal;
} return await base.SendAsync(request, cancellationToken);
}
}

3. Web API的示例实现代码:

public class PostsController : ApiController
{
[Route("blog/posts/sitehome")]
public async Task<IEnumerable<string>> GetSiteHome()
{
return new string[] { User.Identity.Name };
}
}

四、Client得到Resouce Server的响应结果

根据上面的Resouce Server中Web API的示例实现代码,得到的结果是:

["client:m.cnblogs.com"] 

小结

看起来比较简单,但实际摸索的过程是曲折的。分享出来,也许可以让初次使用DotNetOpenAuth的朋友少走一些弯路。

【参考资料】

The OAuth 2.0 Authorization Framework

Claim-based-security for ASP.NET Web APIs using DotNetOpenAuth

Implementing an API Key with DotNetOpenAuth

 
 
 

实现Client Credentials Grant的更多相关文章

  1. 在ASP.NET中基于Owin OAuth使用Client Credentials Grant授权发放Token

    OAuth真是一个复杂的东东,即使你把OAuth规范倒背如流,在具体实现时也会无从下手.因此,Microsoft.Owin.Security.OAuth应运而生(它的实现代码在Katana项目中),帮 ...

  2. [OAuth]基于DotNetOpenAuth实现Client Credentials Grant

    Client Credentials Grant是指直接由Client向Authorization Server请求access token,无需用户(Resource Owner)的授权.比如我们提 ...

  3. (转)基于OWIN WebAPI 使用OAuth授权服务【客户端模式(Client Credentials Grant)】

    适应范围 采用Client Credentials方式,即应用公钥.密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open ...

  4. 基于 IdentityServer3 实现 OAuth 2.0 授权服务【客户端模式(Client Credentials Grant)】

    github:https://github.com/IdentityServer/IdentityServer3/ documentation:https://identityserver.githu ...

  5. 基于OWIN WebAPI 使用OAuth授权服务【客户端模式(Client Credentials Grant)】

    适应范围 采用Client Credentials方式,即应用公钥.密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open ...

  6. OAuth2.0学习(1-7)授权方式4-客户端模式(Client Credentials Grant)

    授权方式4-客户端模式(Client Credentials Grant) 客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提 ...

  7. Oauth Client Credentials Grant

    http://www.cnblogs.com/dudu/p/4569857.html OAuth真是一个复杂的东东,即使你把OAuth规范倒背如流,在具体实现时也会无从下手.因此,Microsoft. ...

  8. 基于OWIN WebAPI 使用OAuth授权服务【客户端验证授权(Resource Owner Password Credentials Grant)】

    适用范围 前面介绍了Client Credentials Grant ,只适合客户端的模式来使用,不涉及用户相关.而Resource Owner Password Credentials Grant模 ...

  9. 使用Resource Owner Password Credentials Grant授权发放Token

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

随机推荐

  1. 数据库性能监测工具——SQL Server Profiler

    使用SQL Server Profiler 进行sql监控需要一些设置: 其他的就是进行分析了~ 清除SQL SERVER缓存 常用的方法: DBCC DROPCLEANBUFFERS 从缓冲池中删除 ...

  2. 第17章 中介者模式(Mediator Pattern)

    原文 第17章 中介者模式(Mediator Pattern) 中介者模式  概述:   在软件开发中,我们有时会碰上许多对象互相联系互相交互的情况,对象之间存在复杂的引用关系,当需求更改时,对系统进 ...

  3. javascript系列之变量对象

    原文:javascript系列之变量对象 引言 一般在编程的时候,我们会定义函数和变量来成功的构造我们的系统.但是解析器该如何找到这些数据(函数,变量)呢?当我们引用需要的对象时,又发生了什么了? 很 ...

  4. ios 调节器 modal 得知

    代码中创建: 1.appdelegate 该contoller放置controller下一个 - (BOOL)application:(UIApplication *)application didF ...

  5. 远程数据client交换器

    不太繁忙的文本. 要被写入

  6. MVC自定义配置

    ASP.NET 5 入门 (2) – 自定义配置 ASP.NET 5 理解和入门 建立和开发ASP.NET 5 项目 初步理解ASP.NET5的配置 正如我的第一篇文章ASP.NET 5 (vNext ...

  7. elasticsearch的rest搜索--- 查询

    目录: 一.针对这次装B 的解释 二.下载,安装插件elasticsearch-1.7.0   三.索引的mapping 四. 查询 五.对于相关度的大牛的文档 四. 查询 1. 查询的官网的文档   ...

  8. ExtJS得知--------Ext.Element学习的查询方法(示例)

    详细实例:(实验结果可复制代码后进行演示) Ext.onReady(function(){ Ext.create('Ext.panel.Panel',{//创建一个面板 title:'我的面板' , ...

  9. HDU 2070 Fibbonacci Number

    Fibbonacci Number Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  10. sql server drop talbe 自动删除关联的外键 ,权限体系(一)

    if object_id('Proc_DropTableWithFK') is not null begin drop proc dbo.Proc_DropTableWithFK end GO ) a ...