博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
开箱即用 - jwt 无状态分布式授权
阅读量:6452 次
发布时间:2019-06-23

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

原文:

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

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

img_079d9a0146cfcee54c241794ce3b9086.png

从客户端请求服务器获取token, 用该token 去访问实现了jwt认证的web服务器。 token 可保存自定义信息,如用户基本信息, web服务器用key去解析token,就获取到请求用户的信息了;

很方便解决跨域授权的问题,因为跨域无法共享cookie,.net平台集成的 FormAuthentication 认证系统是基于Session保存授权信息,拿不到cookie就无法认证,用jwt完美解决了。
很多时候,web服务器和授权服务器是同一个项目,所以也可以用以下架构:
img_630e79a5924d2fa7499843d86ccecba5.png

实现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 类代码

///      /// 自定义 jwt token 的格式     ///     public class CustomJwtFormat : ISecureDataFormat
{ 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类代码

///     /// 自定义 jwt oauth 的授权验证    ///     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(null);            }            var ticket = new AuthenticationTicket(SetClaimsIdentity(context, userid, username), new AuthenticationProperties());            context.Validated(ticket);            return Task.FromResult(null);        }        public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)        {            context.Validated();            return Task.FromResult(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

使用

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

  1. 获取token

    img_495bde4612991c0a31cb0a120870e15d.png

  2. 用token请求数据

    img_9fcf01e281a780ebeb25191e3ed55766.png

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

Authorization   Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyaWQiOiIxIiwidXNlcmNvZGUiOiIxIiwiaXNzIjoidGVzdCIsImF1ZCI6IkFueSIsImV4cCI6MTQ4NzI0MTQ5MCwibmJmIjoxNDg0NjQ5NDkwfQ.RaWlJC3OF0RNz4mLtuW4uQtRKDHF8RXwZwzIcbZoNOo

JWT缺点

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

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

你可能感兴趣的文章
如何在linux系统下配置共享文件夹,如何在windows和Linux系统之间共享文件夹.doc
查看>>
thinkpad装linux无线网卡驱动,ThinkPad E530 Fedora 20 下无线网卡驱动的安装
查看>>
linux操作系统加固软件,系统安全:教你Linux操作系统的安全加固
查看>>
linux中yum源安装dhcp,24.Linux系统下动态网络源部署方法(dhcpd)
查看>>
linux屏幕复制显示出来的,linux – stdout到gnu屏幕复制缓冲区
查看>>
一起学Shell(十)之可称植性议题与扩展
查看>>
部署Ganglia监控Hadoop&Hbase
查看>>
gitlab的用户使用手册
查看>>
论Optimizer的工作模式ALL_ROWS&FIRST_ROWS
查看>>
生产环境高并发MySQL SQL语句优化案例
查看>>
Lync 小技巧-24-PDF 加密文件-转-Word-操作手册
查看>>
ASP.NET性能优化之分布式Session
查看>>
TaffyDB Introduction
查看>>
Piwik 1.9.1 发布,网站访问统计系统
查看>>
【转】ie6 png 透明终极解决方案
查看>>
CentOS6.5菜鸟之旅:关于搜索的shell命令
查看>>
扩展ViewFlow避免和ViewPager滑动冲突,同时支持无限循环,并完美和CircleFlowIndicator结合...
查看>>
VC++之自定义消息
查看>>
JAVA数组的定义及用法
查看>>
Robots协议具体解释
查看>>