zoukankan      html  css  js  c++  java
  • 【干货】基于Owin WebApi 使用OAuth2进行客户端授权服务

    前言:采用Client Credentials方式,即密钥key/password,场景一般是分为客户端限制必须有权限才能使用的模块,这和微信公众号开放平台很类似。

    让用户通过客户端去获取自己的token,在根据这个token去获取资源。

    本地登录凭据流

    1. 用户输入名称和密码到客户端。
    2. 客户端将这些凭据发送到授权服务器。
    3. 授权服务器验证凭据并返回访问令牌。
    4. 要访问受保护资源,客户端在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中,这样的话,类似于一个微信身份授权的功能基本上就是这样了。

  • 相关阅读:
    WTL自绘表指针
    QQ日志搬家工具 1.0
    一个消失很久的首页
    共享.net PE文件结构浏览器+名称混淆 + 16进制结构图 (源码)
    JavaScript中Array 对象相关的几个方法
    ASP.NET底层架构
    ASP.NET 2.0 正式版中无刷新页面的开发
    ASP.NET组件设计Step by Step(9)
    ASP.NET组件设计Step by Step(8)
    ajax上传(xmlhttp上传文件突破大小限制)
  • 原文地址:https://www.cnblogs.com/ZaraNet/p/10006968.html
Copyright © 2011-2022 走看看