zoukankan      html  css  js  c++  java
  • .NET 请求认证之access-token(oauth2.0与owin的结合)

          公司对外开放的接口,大多需要请求认证,如微信,阿里等。最近我刚好在搭建webapi框架。记录一下自己的理解。

    一:请求认证的目的

      之所以要对我们的接口进行请求认证,就是为了安全考虑的。以前都是在用别人给我的规则去生成token,现在也轮到自己开发了。嘿嘿

    二:开发思路

      1:请求接口之前,用户必须先去请求获得我们的access-token。每次请求必须得带上access-token来请求我的接口。否则我们会拒绝外部请求。 

      2:access-token有时间的限制,过期的请求我们依然会拒绝。

      3:对不同的外部者,应有不同的clientID。以便分配不同的权限。以后不合作了,我们可以取消他们的认证,并不会影响其他的客户。类似于微信的 Appid,Appsecret

    三:创建Access-Token

          在api项目里token验证发生在进入接口之前,需要有一个启动文件来执行token的判断。在API项目下创建Startup.cs类。

         我们需要在Nuget引用以下DLL:

    • Microsoft.Owin.Security.OAuth
    • Microsoft.Owin.Security
    • Microsoft.Owin
    • Microsoft.Owin.Host.SystemWeb
    • OWIN
    • Microsoft ASP.Net Web API 2.2 OWIN
    • Microsoft ASP.Net Identity OWIN
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Http;
    using Bn.Common;
    using Microsoft.Owin;
    using Microsoft.Owin.Cors;
    using Microsoft.Owin.Security;
    using Microsoft.Owin.Security.OAuth;
    using Owin;
    
    [assembly: OwinStartup(typeof(BnWebApi.Startup))]
    
    namespace BnWebApi
    {
        /// <summary>
        /// wuchen19-4-15
        /// </summary>
        public partial class Startup
        {
            //public void Configuration(IAppBuilder app)
            //{
            //    ConfigureAuth(app);
            //}
            public void Configuration(IAppBuilder app)
            {
                HttpConfiguration config = new HttpConfiguration();
                WebApiConfig.Register(config);
                ConfigureOAuth(app);
                app.UseCors(CorsOptions.AllowAll);
                app.UseWebApi(config);
            }
    
            public void ConfigureOAuth(IAppBuilder app)
            {
                var OAuthServerOptions = new OAuthAuthorizationServerOptions()
                {
                    AllowInsecureHttp = true, //允许客户端使用Http协议请求
                    TokenEndpointPath = new PathString("/token"), //请求地址
                    //AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), //token过期时间
                    AccessTokenExpireTimeSpan = TimeSpan.FromHours(1),
                    Provider = new SimpleAuthorizationServerProvider(),//提供认证策略
                    RefreshTokenProvider = new SimpleRefreshTokenProvider() //refresh_token 授权服务
                };
                app.UseOAuthAuthorizationServer(OAuthServerOptions);
                app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
            }
    
    
    
    
        }
    }

    这个SimpleRefreshTokenProvider()方法就是我们验证Client信息和生成Token的地方

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Text;
    using System.Threading.Tasks;
    using Microsoft.Owin.Security;
    using Microsoft.Owin.Security.OAuth;
    using  System.Configuration;
    
    namespace Bn.Common
    {
        /// <summary>
        /// Token验证    wuchen  5-17
        /// </summary>
        public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
        {
    
    
            #region  AccessToken生成机制   密码模式   
            ////Oauth AccessToken  grant_type=password
    
            //public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
            //{
            //    await Task.Factory.StartNew(() => context.Validated());
            //}
            //public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
            //{
            //    await Task.Factory.StartNew(() => context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }));
            //    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
            //    var bnauth = ConfigurationManager.AppSettings["Oauth"];  //BnUser-123456
            //    var bnstr = bnauth.Split('-');
            //    var bnuser = bnstr[0];
            //    var bnpassword = bnstr[1];
            //    if (context.UserName != bnuser || context.Password != bnpassword)
            //    {
            //        context.SetError("invalid_client", "账号密码认证失败");
            //         return;
            //    }
            //    identity.AddClaim(new Claim("sub", context.UserName));
            //    identity.AddClaim(new Claim("role", "user"));
            //    context.Validated(identity);
            //}
            #endregion
    
    
    
            #region  AccessToken生成机制   客户端模式     
            // grant_type= client_credentials
            public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
            {
                string clientId;
                string clientSecret;
                context.TryGetFormCredentials(out clientId, out clientSecret);
                //验证
                //var bnauth = ConfigurationManager.AppSettings["Oauth"];  //BnUser-123456
                //var bnstr = bnauth.Split('-');
                //var bnuser = bnstr[0];
                //var bnpassword = bnstr[1];
                //if (clientId != bnuser || clientSecret != bnpassword)
                //{
                //    context.SetError("invalid_client", "账号密码认证失败");
                //    return;
                //}
    
                var gkey = ConfigurationManager.AppSettings[clientId];  //BnUser-123456
                if (clientSecret != gkey)
                {
                    context.SetError("invalid_client", "账号密码认证失败");
                    return;
                }
    
                context.OwinContext.Set("as:client_id", clientId);
                await Task.Factory.StartNew(() => context.Validated(clientId));
                //context.Validated(clientId);
            }
            /// <summary>
            ///     客户端授权[生成access token]
            /// </summary>
            /// <param name="context"></param>
            /// <returns></returns>
            public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
            {
                var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
                oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, context.OwinContext.Get<string>("as:client_id")));
                var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties { AllowRefresh = true });
                context.Validated(ticket);
                return base.GrantClientCredentials(context);
            }
            #endregion
    
        }
    }

    两种模式都是可以用的。。密码模式和客户端模式。GrantClientCredentials方法为我们生成Token的方法。。有了这些我们就可以生成token啦。

    Oauth支持的5类 grant_type 及说明(
    authorization_code — 授权码模式(即先登录获取code,再获取token)
    password — 密码模式(将用户名,密码传过去,直接获取token)
    client_credentials — 客户端模式(无用户,用户向客户端注册,然后客户端以自己的名义向’服务端’获取资源)
    implicit — 简化模式(在redirect_uri 的Hash传递token; Auth客户端运行在浏览器中,如JS,Flash)
    refresh_token — 刷新access_token) 

    四:获取Token

    输入参数:grant_type:验证模式 ,   client_id :服务端定义 ,  client_secret:秘钥 服务端和客户端共同保存   类似于微信的Appsecrret

    生成项目,然后本地用Postman调试

    返回的参数分别是:access_token:我们需要的token        token_type :bearer  (协议固定)         expires_in:有效期(可以自定义)        refresh_token:token重新过期后,重新获取token用到(暂时没用)

      五:使用access_token访问接口路由

     在Webapi中 ,我们用在方法加上 Authorize ,来表示这个方法访问需要授权, 如果不加Authorize ,那么token就没有意义。。  如下

     

    我们不带token访问一下看看:

     显示已拒绝我们的请求授权。

     加了access-Token之后,注意token放的位置,在请求头Headers里  添加 Authorization:bearer token。      bearer与token之间有一个空格

    验证的过程,是在我们Oauth2.0封装起来啦,可以查看。

    到这里,用Oauth2.0加Owin的Webapi请求验证--accesstoken完成。。基本每一步都有注释,很好理解

         

          简单的两句代码,双倍的快乐

  • 相关阅读:
    POJ 2175 Evacuation Plan 费用流 负圈定理
    POJ 2983 Is the Information Reliable? 差分约束
    codeforces 420B Online Meeting
    POJ 3181 Dollar Dayz DP
    POJ Ant Counting DP
    POJ 1742 Coins DP 01背包
    中国儒学史
    产品思维30讲
    Java多线程编程核心技术
    编写高质量代码:改善Java程序的151个建议
  • 原文地址:https://www.cnblogs.com/cr-cool/p/10882831.html
Copyright © 2011-2022 走看看