博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
基于OWIN WebAPI 使用OAuth授权服务【客户端模式(Client Credentials Grant)】
阅读量:6326 次
发布时间:2019-06-22

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

适应范围

采用Client Credentials方式,即应用公钥、密钥方式获取Access Token,适用于任何类型应用,但通过它所获取的Access Token只能用于访问与用户无关的Open API,并且需要开发者提前向开放平台申请,成功对接后方能使用。认证服务器不提供像用户数据这样的重要资源,仅仅是有限的只读资源或者一些开放的 API。例如使用了第三方的静态文件服务,如Google Storage或Amazon S3。这样,你的应用需要通过外部API调用并以应用本身而不是单个用户的身份来读取或修改这些资源。这样的场景就很适合使用客户端证书授权,通过此授权方式获取Access Token仅可访问平台授权类的接口。

比如获取App首页最新闻列表,由于这个数据与用户无关,所以不涉及用户登录与授权,但又不想任何人都可以调用这个WebAPI,这样场景就适用[例:比如授权]。

Client Credentials Grant:
+---------+                                  +---------------+     |         |                                  |               |     |         |>--(A)- Client Authentication --->| Authorization |     | Client  |                                  |     Server    |     |         |<--(B)---- Access Token ---------<|               |     |         |                                  |               |     +---------+                                  +---------------+                     Figure 6: Client Credentials Flow

基本流程

 

A.客户端提供用户名和密码交换令牌

B.认证服务器验证通过,发放令牌,后面根据这个令牌获取资源即可

服务实现

使用WEBAPI基于实现,源码: ;新建一个不启用身份验证空的WEBAPI项目

安装包

Install-Package Microsoft.AspNet.Identity.Owin

Install-Package Microsoft.Owin.Security.OAuth
Install-Package Microsoft.AspNet.WebApi.Owin
Install-Package Microsoft.AspNet.WebApi.WebHost
Install-Package Microsoft.Owin.Host.SystemWeb

OWIN WEBAPI

[assembly: OwinStartup(typeof(Startup))]namespace OAuth2.App_Start{    public partial class Startup    {        public void Configuration(IAppBuilder app)        {            ConfigureAuth(app);        }    }}    public partial class Startup    {        public void ConfigureAuth(IAppBuilder app)        {            /*              app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions             {                 TokenEndpointPath = new PathString("/token"),                 Provider = new ApplicationOAuthProvider(),                 AccessTokenExpireTimeSpan = TimeSpan.FromHours(2),                 AuthenticationMode = AuthenticationMode.Active,                 //HTTPS is allowed only AllowInsecureHttp = false                 AllowInsecureHttp = true                 //ApplicationCanDisplayErrors = false             });             app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());             */            app.UseOAuthBearerTokens(new OAuthAuthorizationServerOptions            {                TokenEndpointPath = new PathString("/token"),                Provider = new ApplicationOAuthProvider(),                //RefreshTokenProvider = new ApplicationRefreshTokenProvider(),                AccessTokenExpireTimeSpan = TimeSpan.FromHours(2),                AuthenticationMode = AuthenticationMode.Active,                //HTTPS is allowed only AllowInsecureHttp = false                AllowInsecureHttp = true                //ApplicationCanDisplayErrors = false            });        }    }    public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider    {        /*         private OAuth2ClientService _oauthClientService;         public ApplicationOAuthProvider()         {             this.OAuth2ClientService = new OAuth2ClientService();         }         */        ///         /// 验证客户[client_id与client_secret验证]        ///         ///         /// 
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { //http://localhost:48339/token //grant_type=client_credentials&client_id=irving&client_secret=123456 string client_id; string client_secret; context.TryGetFormCredentials(out client_id, out client_secret); if (client_id == "irving" && 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); } /// /// 客户端授权[生成access token] /// /// ///
public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context) { /* var client = _oauthClientService.GetClient(context.ClientId); oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, client.ClientName)); */ 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); } /// /// 刷新Token[刷新refresh_token] /// /// ///
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"); } else { //Additional claim is needed to separate access token updating from authentication //requests in RefreshTokenProvider.CreateAsync() method } return base.GrantRefreshToken(context); } public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context) { if (context.ClientId == "irving") { var expectedRootUri = new Uri(context.Request.Uri, "/"); if (expectedRootUri.AbsoluteUri == context.RedirectUri) { context.Validated(); } } return Task.FromResult(null); } }

资源服务

///     ///客户端模式【Client Credentials Grant】    ///http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api    ///     [RoutePrefix("api/v1/oauth2")]    public class OAuth2Controller : ApiController    {        ///         /// 获得资讯        ///         /// 
[Authorize] [Route("news")] public async Task
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.ToJson() }); } }

启用授权验证[WebApiConfig]

在ASP.NET Web API中启用Token验证,需要加上[Authorize]标记,并且配置默认启用验证不记名授权方式

// Web API configuration and services            // Configure Web API to use only bearer token authentication.            config.SuppressDefaultHostAuthentication();            config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

客户端

获得票据

服务端[/token]获取token需要三个参数

POST HTTP/1.1

Content-type:application/json;charset=UTF-8
grant_type=client_credentials&client_id=irving&client_secret=123456
 
{"access_token":"qghSowAcM9Ap7yIiyZ6i52VOk4NWBpgDDJZ6jf-PdAeP4roFMlGhKUV_Kg_ow0QgTXBKaPzIFBLzdc6evBUPVOaV8Op0wsrUwwKUjRluAPAQmw3MIm8MtmtC0Vfp7ZByuvvMy21NbpRBZcajQxzunJGPIqbdPMYs8e279T5UMmgpBVZJuC4N6d-mxk3DMN2-42cOxz-3k6J-7yXCVYroEh6txjZW03ws155LswIg0yw","token_type":"bearer","expires_in":7199}

请求资源

设置HTTP头 Authorization: Bearer {THE TOKEN}

GET HTTP/1.1

Authorization: Bearer qghSowAcM9Ap7yIiyZ6i52VOk4NWBpgDDJZ6jf-PdAeP4roFMlGhKUV_Kg_ow0QgTXBKaPzIFBLzdc6evBUPVOaV8Op0wsrUwwKUjRluAPAQmw3MIm8MtmtC0Vfp7ZByuvvMy21NbpRBZcajQxzunJGPIqbdPMYs8e279T5UMmgpBVZJuC4N6d-mxk3DMN2-42cOxz-3k6J-7yXCVYroEh6txjZW03ws155LswIg0yw
grant_type=client_credentials&client_id=irving&client_secret=123456

{"IsError":true,"Msg":"","Data":"iphone It's about news !!! token expires: {\".refresh\":\"True\",\".issued\":\"Mon, 29 Jun 2015 02:47:12 GMT\",\".expires\":\"Mon, 29 Jun 2015 04:47:12 GMT\"}"}

客户端测试

///     ///客户端模式【Client Credentials Grant】    ///http://www.asp.net/web-api/overview/security/individual-accounts-in-web-api    ///     [RoutePrefix("api/v1/oauth2")]    public class OAuth2Controller : ApiController    {        ///         /// 获取token        ///         /// 
[Route("token")] public async Task
GetTokenAsync() { //获得token var dict = new SortedDictionary
(); dict.Add("client_id", "irving"); dict.Add("client_secret", "123456"); dict.Add("grant_type", "client_credentials"); var data = await (@"http://" + Request.RequestUri.Authority + @"/token").PostUrlEncodedAsync(dict).ReceiveJson
(); //根据token获得咨询信息 [Authorization: Bearer {THE TOKEN}] //var news = await (@"http://" + Request.RequestUri.Authority + @"/api/v1/oauth2/news").WithHeader("Authorization", "Bearer " + data.access_token).GetAsync().ReceiveString(); var news = await (@"http://" + Request.RequestUri.Authority + @"/api/v1/oauth2/news").WithOAuthBearerToken(data.access_token).GetAsync().ReceiveString(); return Ok(new { IsError = true, Msg = data, Data = news }); } } public class Token { public string access_token { get; set; } public string token_type { get; set; } public string expires_in { get; set; } }

REFER:

Secure a Web API with Individual Accounts and Local Login in ASP.NET Web API 2.2
 
Use OWIN to Self-Host ASP.NET Web API 2
OWIN OAuth 2.0 Authorization Server
ASP.Net MVC: Creating an OAuth client credentials grant type token endpoint
OwinStartup not Starting … Why?
[OAuth]基于DotNetOpenAuth实现Client Credentials Grant
一些例子

转载地址:http://ecgaa.baihongyu.com/

你可能感兴趣的文章
并查集的应用之求解无向图中的连接分量个数
查看>>
7个神奇的jQuery 3D插件
查看>>
在线浏览PDF之PDF.JS (附demo)
查看>>
波形捕捉:(3)"捕捉设备"性能
查看>>
AliOS Things lorawanapp应用介绍
查看>>
美国人的网站推广方式千奇百怪
查看>>
java web学习-1
查看>>
用maven+springMVC创建一个项目
查看>>
linux设备驱动第四篇:以oops信息定位代码行为例谈驱动调试方法
查看>>
redis知识点整理
查看>>
Hello World
查看>>
Spring3全注解配置
查看>>
ThreadLocal真会内存泄露?
查看>>
IntelliJ IDEA
查看>>
低版本mybatis不能用PageHeper插件的时候用这个分页
查看>>
javaweb使用自定义id,快速编码与生成ID
查看>>
[leetcode] Add Two Numbers
查看>>
elasticsearch suggest 的几种使用-completion 的基本 使用
查看>>
04-【MongoDB入门教程】mongo命令行
查看>>
Hadoop HA元数据备份
查看>>