http://www.cnblogs.com/dudu/p/4569857.html

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

这篇博文试图通过一个简单的示例分享一下如何基于Microsoft.Owin.Security.OAuth,使用Client Credentials Grant授权方式给客户端发放access token。

Client Credentials Grant的授权方式就是只验证客户端(Client),不验证用户(Resource Owner),只要客户端通过验证就发access token。举一个对应的应用场景例子,比如我们想提供一个“获取网站首页最新博文列表”的WebAPI给iOS App调用。由于这个数据与用户无关,所以不涉及用户登录与授权,不需要Resource Owner的参与。但我们不想任何人都可以调用这个WebAPI,所以要对客户端进行验证,而使用OAuth中的 Client Credentials Grant 授权方式可以很好地解决这个问题。

具体实现方式如下:

1)用Visual Studio 2013/2015创建一个Web API项目,VS会生成一堆OAuth相关代码。

2)打开Startup.Auth.cs ,精简一下代码,我们只需要实现以Client Credentials Grant授权方式拿到token,其它无关代码全部清除,最终剩下如下代码:

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() 这两个方法。代码如下:

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 进行验证。

在 GrantClientCredentials() 方法中对客户端进行授权,授了权就能发 access token 。

这样,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);
}
}
 

最新文章

  1. 备份了我的CSDN博客
  2. form.submit() not a function的元凶
  3. Qt之多窗口切换
  4. ARM NEON 编程系列2 - 基本指令集
  5. test命令的用法
  6. ubuntu下使用C语言开发一个cgi程序
  7. HTML5实现图片选择并预览
  8. WPF:在XmlDataProvider上使用主-从绑定(Master-Detail Binding)
  9. CodeForces 620E New Year Tree
  10. python针对端口11211进行全网收集
  11. Git使用九:合并和删除分支
  12. 修改Vim内注释字体颜色
  13. Linux每天一个命令:grep
  14. vins-mono代码解读
  15. 赵炯博士《Linux内核完全注释》
  16. 通过flask中的Response返回json数据
  17. WebView之加载网页时增加进度提示
  18. JMS之——ActiveMQ时抛出的错误Could not connect to broker URL-使用线程池解决高并发连接
  19. HDU 5738 Eureka 统计共线的子集个数
  20. [javaEE] http协议详细

热门文章

  1. J2EE分布式服务基础之RPC
  2. Python List reverse()方法
  3. 关于Intellij IDEA导入jdk出现异常
  4. java中List、Map、Set、Collection、Stack、Queue等的使用
  5. 蓝桥杯 算法训练 ALGO-149 5-2求指数
  6. HDU1021(模运算)
  7. 转载:MongoDB 在 58 同城百亿量级数据下的应用实践
  8. suse 源的添加与删除,以及源地址
  9. 类型:NodeJs;问题:默认IE的编码为utf8;结果:IE不能自动选择UTF-8编码解决办法
  10. C语言学习笔记--数组参数和指针参数