【干货】基于Owin WebApi 使用OAuth2进行客户端授权服务
前言:采用Client Credentials方式,即密钥key/password,场景一般是分为客户端限制必须有权限才能使用的模块,这和微信公众号开放平台很类似。

让用户通过客户端去获取自己的token,在根据这个token去获取资源。
本地登录凭据流
- 用户输入名称和密码到客户端。
- 客户端将这些凭据发送到授权服务器。
- 授权服务器验证凭据并返回访问令牌。
- 要访问受保护资源,客户端在HTTP请求的Authorization标头中包含访问令牌。
服务实现:
使用WebApi基于Microsoft.Owin.Security.OAuth实现,新建一个空为WebApi项目。
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OAuth;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web; namespace ApiThrottleDemo
{
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{ /// <summary>
/// 验证客户[client_id与client_secret验证]
/// </summary>
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
//http://localhost:48339/token
string client_id;
string client_secret;
context.TryGetFormCredentials(out client_id, out client_secret);
if (client_id == "zara" && client_secret == "123456")
{
context.Validated(client_id);
}
else
{
//context.Response.StatusCode = Convert.ToInt32(HttpStatusCode.OK);
context.SetError("invalid_client", "client is not valid");
}
return base.ValidateClientAuthentication(context);
} /// <summary>
/// 客户端授权[生成access token]
/// </summary>
public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
{ var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, "iphone"));
var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties() { AllowRefresh = true });
context.Validated(ticket);
return base.GrantClientCredentials(context);
} /// <summary>
/// 刷新Token[刷新refresh_token]
/// </summary>
public override Task GrantRefreshToken(OAuthGrantRefreshTokenContext context)
{
//enforce client binding of refresh token
if (context.Ticket == null || context.Ticket.Identity == null || !context.Ticket.Identity.IsAuthenticated)
{
context.SetError("invalid_grant", "Refresh token is not valid");
}
return base.GrantRefreshToken(context);
}
}
}
在此其中呢,需要继承OAuthAuthorizationServerProvider,并重写自己想重写的方法,其内部定义下图所示:

当然这还没完,我们还需要去配置应用程序。在Startup.cs,我们要开启BearerToken认证模式;该Provider属性指定了一个插入OWIN中间件的提供程序,并处理由中间件引发的事件。
以下是应用想要获取令牌时的基本流程:
要获取访问令牌,应用程序会向〜/ Token发送请求。
OAuth中间件调用GrantResourceOwnerCredentials提供程序。
提供程序调用ApplicationUserManager以验证凭据并创建声明标识。
如果成功,则提供程序会创建一个身份验证票证,用于生成令牌。
app.UseOAuthBearerTokens(new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/token"),
Provider = new ApplicationOAuthProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromHours(2),
AuthenticationMode = AuthenticationMode.Active,
AllowInsecureHttp = true
});
其中AccessTokenExpireTimeSpan参数是token过期时间,AllowInsecureHttp 是否开启安全验证,TokenEndpointPath就是你获取token对于服务器的相对路径,那我们都知道用户只能访问我们的Api,那如何在api上去走Oauth呢?
客户端获取票据
在控制器种创建一个控制器,命名为:OAuth2Controller。
[RoutePrefix("api/v1/oauth2")]
public class OAuth2Controller : ApiController
{
[Authorize]
[Route("news")]
public async Task<IHttpActionResult> GetNewsAsync()
{
var authentication = HttpContext.Current.GetOwinContext().Authentication;
var ticket = authentication.AuthenticateAsync("Bearer").Result;
var claimsIdentity = User.Identity as ClaimsIdentity;
var data = claimsIdentity.Claims.Where(c => c.Type == "urn:oauth:scope").ToList();
var claims = ((ClaimsIdentity)Thread.CurrentPrincipal.Identity).Claims;
return Ok(new { IsError = true, Msg = string.Empty, Data = Thread.CurrentPrincipal.Identity.Name + " It's about news !!! token expires: " + ticket.Properties.Dictionary.ToString() });
}
}
启用授权验证[WebApiConfig]
在ASP.NET Web API中启用Token验证,需要加上[Authorize]标记,并且配置默认启用验证不记名授权方式
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
服务端[/token]获取token需要三个参数,我们使用大家熟悉的PostMan去试一试吧,启动项目。

那我们不难看到,已经成功获取了access_token,至于这个token的值,只要你的client_id不同它就一定是不会相同的(实在不行你可以搞个GUID),那么我们再构建一个ajax去模拟的获取token吧。
做个简单的页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="http://libs.baidu.com/jquery/2.1.1/jquery.min.js"></script>
</head>
<body>
<input type="text" placeholder="client_id"/><br />
<input type="text" placeholder="client_secret"/><br />
<input type="text" placeholder="your_token"/><br />
<button>获取token</button>
</body>
<script>
$(function () {
$("button").click(function () {
$.ajax({
url: "http://localhost:58560/token",
type: "post",
data: "grant_type=client_credentials&client_id=zara&client_secret=123456",
success: function (res) {
console.log(res);
}
})
})
})
</script>
</html>
这是生成的token。

最后总结,你可以在ValidateClientAuthentication中进行身份判断,如果有这个身份,那么我就存储DB中,这样的话,类似于一个微信身份授权的功能基本上就是这样了。
【干货】基于Owin WebApi 使用OAuth2进行客户端授权服务的更多相关文章
- Owin中间件搭建OAuth2.0认证授权服务体会
继两篇转载的Owin搭建OAuth 2.0的文章,使用Owin中间件搭建OAuth2.0认证授权服务器和理解OAuth 2.0之后,我想把最近整理的资料做一下总结. 前两篇主要是介绍概念和一个基本的D ...
- 基于OWIN WebAPI 使用OAUTH2授权服务【授权码模式(Authorization Code)】
之前已经简单实现了OAUTH2的授权码模式(Authorization Code),但是基于JAVA的,今天花了点时间调试了OWIN的实现,基本就把基于OWIN的OAUHT2的四种模式实现完了.官方推 ...
- 使用Owin中间件搭建OAuth2.0认证授权服务器
前言 这里主要总结下本人最近半个月关于搭建OAuth2.0服务器工作的经验.至于为何需要OAuth2.0.为何是Owin.什么是Owin等问题,不再赘述.我假定读者是使用Asp.Net,并需要搭建OA ...
- Spring Cloud Zuul 网关使用与 OAuth2.0 认证授权服务
API 网关的出现的原因是微服务架构的出现,不同的微服务一般会有不同的服务地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题: 客户端会 ...
- (转)基于OWIN WebAPI 使用OAuth授权服务【客户端模式(Client Credentials Grant)】
适应范围 采用Client Credentials方式,即应用公钥.密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open ...
- 基于OWIN WebAPI 使用OAuth授权服务【客户端验证授权(Resource Owner Password Credentials Grant)】
适用范围 前面介绍了Client Credentials Grant ,只适合客户端的模式来使用,不涉及用户相关.而Resource Owner Password Credentials Grant模 ...
- 基于OWIN WebAPI 使用OAuth授权服务【客户端模式(Client Credentials Grant)】
适应范围 采用Client Credentials方式,即应用公钥.密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open ...
- 基于OWIN+DotNetOpenOAuth实现OAuth2.0
这几天时间一直在研究怎么实现自己的OAuth2服务器,对于太了解OAuth原理以及想自己从零开始实现的,我建议可以参考<Apress.Pro ASP.NET Web API Security&g ...
- Spring Cloud 微服务中搭建 OAuth2.0 认证授权服务
在使用 Spring Cloud 体系来构建微服务的过程中,用户请求是通过网关(ZUUL 或 Spring APIGateway)以 HTTP 协议来传输信息,API 网关将自己注册为 Eureka ...
随机推荐
- 结对开发项目--石家庄地铁web版
一.功能要求 1.数据库设计:将石家庄地铁线路图的各个线路,各个站点,换乘信息等用数据库的形式保存起来,应该保存的信息有 {线路号,线路的各个站名,车站的换乘信息}. 2.站点查询:用户可以输入任一一 ...
- 代码调用t.cn接口生成短址
新浪短网址接口的稳定性和跳转速度还是很给力的,现给出其API说明. 该接口支持两种返回格式:xml和json 对应的URL请求地址为: xml:http://api.t.sina.com.cn/sho ...
- Markdown初使用
Markdown是一种纯文本格式的标记语言.通过简单的标记语法,它可以使普通文本内容具有一定的格式. 相比WYSIWYG编辑器 优点:1.因为是纯文本,所以只要支持Markdown的地方都能获得一样的 ...
- Android全平台书籍
<Android Database Programming>:全书研究Android平台下的数据库技术. <Android Application Programming with ...
- APM和PIX飞控日志分析入门贴
我们在飞行中,经常会碰到各种各样的问题,经常有模友很纳闷,为什么我的飞机会这样那样的问题,为什么我的飞机会炸机,各种问题得不到答案是一件非常不爽的问题,在APM和PIX飞控中,都有记录我们整个飞行过程 ...
- python爬取珞珈1号卫星数据
首先登录珞珈一号数据系统查询想要的数据 利用浏览器审查元素获取包含下载信息的源码 将最右侧的table相关的网页源码copy到剪切板备用 利用python下载数据 ## utf-8 import re ...
- VMware手动添加centos7硬盘图文操作及分区超详细
先设置虚拟机 启动的虚拟机,新关机再设置 1.选择指定虚拟机,点击硬盘 2.虚拟机设置,点击左下角“添加” 3.硬件类型选择硬盘,点击下一步 4.添加硬件向导默认就行,下一步 5.选择磁盘,默认选中, ...
- 匿名函数 javascript
匿名函数: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...
- javascript 变量的引入、变量的声明、变量的初始化
变量的引入及声明和初始化: 变量: 操作的数据都是在内存中操作 Js中存储数据使用变量的方式(名称,值--->数据) Js中声明变量都用var--->存储数据,数据应该有对应的数据类型 存 ...
- iOS 开发中keyChain的使用
我们开发中很多数据都是直接存储到本地沙盒中的,这样当应用程序被卸载后,本地的数据都会被删除.如果我们不想让数据在卸载程序的时候丢失,我们可以用KeyChain来存储我们想要的数据.苹果提供了原生的一套 ...