zoukankan      html  css  js  c++  java
  • 开箱即用

    尊重原创:https://www.cnblogs.com/grissom007/p/6294746.html

    基于JWT(Json Web Token)的授权方式

    JWT 是JSON风格轻量级的授权和身份认证规范,可实现无状态、分布式的Web应用授权;

    从客户端请求服务器获取token, 用该token 去访问实现了jwt认证的web服务器。 token 可保存自定义信息,如用户基本信息, web服务器用key去解析token,就获取到请求用户的信息了;
    很方便解决跨域授权的问题,因为跨域无法共享cookie,.net平台集成的 FormAuthentication 认证系统是基于Session保存授权信息,拿不到cookie就无法认证,用jwt完美解决了。
    很多时候,web服务器和授权服务器是同一个项目,所以也可以用以下架构:

    实现JWT授权

    1.vs2015 新建一个WebApi,安装下面的库,可用nuget 或 命令安装:

    install-package Thinktecture.IdentityModel.Core
    install-package Microsoft.Owin.Security.Jwt

    2.把Startup.Auth.cs 下的 ConfigureAuth 方法清空掉,改为:

    
        public partial class Startup
        {
            public void ConfigureAuth(IAppBuilder app)
            {
                var issuer = ConfigurationManager.AppSettings["issuer"];
                var secret = TextEncodings.Base64Url.Decode(Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(ConfigurationManager.AppSettings["secret"])));
    
                //用jwt进行身份认证
                app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
                {
                    AuthenticationMode = AuthenticationMode.Active,
                    AllowedAudiences = new[] { "Any" },
                    IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]{
            new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
                    }
                });
    
    
                app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
                {
                    //生产环境设为false
                    AllowInsecureHttp = true,
                    //请求token的路径
                    TokenEndpointPath = new PathString("/oauth2/token"),
                    AccessTokenExpireTimeSpan = TimeSpan.FromDays(30),
                    //请求获取token时,验证username, password
                    Provider = new CustomOAuthProvider(),
                    //定义token信息格式 
                    AccessTokenFormat = new CustomJwtFormat(issuer, secret),
                });
    
            }
        }

    3.ConfigureAuth中的 AccessTokenFormat = new CustomJwtFormat(issuer, secret)是自定义token 保存的信息格式, CustomJwtFormat.cs 类代码

    
        /// <summary> 
        /// 自定义 jwt token 的格式 
        /// </summary>
        public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
        {
            private readonly byte[] _secret;
            private readonly string _issuer;
    
            public CustomJwtFormat(string issuer, byte[] secret)
            {
                _issuer = issuer;
                _secret = secret;
            }
    
            public string Protect(AuthenticationTicket data)
            {
                if (data == null)
                {
                    throw new ArgumentNullException(nameof(data));
                }
    
                var signingKey = new HmacSigningCredentials(_secret);
                var issued = data.Properties.IssuedUtc;
                var expires = data.Properties.ExpiresUtc;
    
                return new JwtSecurityTokenHandler().WriteToken(new JwtSecurityToken(_issuer, "Any", data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey));
            }
    
            public AuthenticationTicket Unprotect(string protectedText)
            {
                throw new NotImplementedException();
            }
        }

    4.ConfigureAuth中的 Provider = new CustomOAuthProvider() 是自定义验证username, password 的,可以用它来实现访问数据库的验证业务逻辑,CustomOAuthProvider.cs类代码

        /// <summary>
        /// 自定义 jwt oauth 的授权验证
        /// </summary>
        public class CustomOAuthProvider : OAuthAuthorizationServerProvider
        {
            public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
            {
                var username = context.UserName;
                var password = context.Password;
                string userid;
                if (!CheckCredential(username, password, out userid))
                {
                    context.SetError("invalid_grant", "The user name or password is incorrect");
                    context.Rejected();
                    return Task.FromResult<object>(null);
                }
                var ticket = new AuthenticationTicket(SetClaimsIdentity(context, userid, username), new AuthenticationProperties());
                context.Validated(ticket);
    
                return Task.FromResult<object>(null);
            }
    
            public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
            {
                context.Validated();
                return Task.FromResult<object>(null);
            }
    
            private static ClaimsIdentity SetClaimsIdentity(OAuthGrantResourceOwnerCredentialsContext context, string userid, string usercode)
            {
                var identity = new ClaimsIdentity("JWT");
                identity.AddClaim(new Claim("userid", userid));
                identity.AddClaim(new Claim("username", usercode));
                return identity;
            }
    
            private static bool CheckCredential(string usernme, string password, out string userid)
            {
                var success = false;
                // 用户名和密码验证
                if (usernme == "admin" && password == "admin")
                {
                    userid = "1";
                    success = true;
                }
                else
                {
                    userid = "";
                }
                return success;
            }
        }

    5.Web.config 添加 issue 和 secret

      <appSettings>
        <add key="issuer" value="test"/>
        <!--32个字符的secret-->
        <add key="secret" value="12345678123456781234567812345678"/>
      </appSettings>

    使用

    强烈建议用 chrome 的 postman 插件来调试

    1. 获取token

    2. 用token请求数据

    header 要添加 Authorization , 值为: Bearer [token], 获取到的 token 替换 [token], 如

    Authorization   Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiIxIiwidXNlcmNvZGUiOiIxIiwiaXNzIjoidGVzdCIsImF1ZCI6IkFueSIsImV4cCI6MTQ4NzI0MTQ5MCwibmJmIjoxNDg0NjQ5NDkwfQ.RaWlJC3OF0RNz4mLtuW4uQtRKDHF8RXwZwzIcbZoNOo

    JWT缺点

    1. 一旦拿到token, 可用它访问服务器,直到过期,中间服务器无法控制它,如是它失效(有解决方案: 在 token 中保存信息,可添加额外的验证,如加一个 flag, 把数据库对应的flag失效,来控制token有效性)。
    2. token 的过期时间设置很关键,一般把它设到凌晨少人访问时失效,以免用户使用过程中失效而丢失数据。
    3. token保存的信息有限,且都是字符串。

    Demo源码

  • 相关阅读:
    CREATE AGGREGATE
    技术文档列表
    jQuery 判断表单中多个 input text 中至少有一个不为空
    Java实现 蓝桥杯 算法提高 奥运会开幕式
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最长滑雪道
    Java实现 蓝桥杯 算法提高 最大值路径
    Java实现 蓝桥杯 算法提高 最大值路径
    Java实现 蓝桥杯 算法提高 最大值路径
  • 原文地址:https://www.cnblogs.com/xiaohouzai/p/8350306.html
Copyright © 2011-2022 走看看