JWT(JSON Web Token)

  • 什么叫JWT
    JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。

    一般来说,互联网用户认证是这样子的。

    1、用户向服务器发送用户名和密码。
    2、服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
    3、服务器向用户返回一个 session_id,写入用户的 Cookie。
    4、用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
    5、服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

    服务器需要保存session,做持久化,这种模式没有分布式架构,无法支持横向扩展,如果真的要的话就必须采用分布式缓存来进行管理Seesion。那JWT相反,它保存的是在客户端,每次请求都将JWT代入服务器,进行签名,权限验证。JWT由客户端请求,服务端生成,客户端保存,服务端验证。

  • JWT的原理与格式

    1. 原理
      在上面,我们也讲过了,简单的来说,我们将服务器需要验证我们的条件(账户,密码等等),发给服务器,服务器认证通过,生成一个JSON对象返回给我们,例如下面。当然,为了防止被篡改,所以我们会将对象加密,再次请求服务器,需要将jwt放在请求头部,传递给服务器,来判断权限等等。

      1. {
      2. "姓名": "张三",
      3. "角色": "管理员",
      4. "到期时间": "2018年7月1日0点0分"
      5. }
    2. 格式

      • 实际格式
      1. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
      2. eyJBIjoiQUFBQSIsIkIiOiJCQkJCIiwiQyI6IkNDQ0MiLCJ1ZXIiOiJ4dWh1YWxlIiwib3BlbmlkIjoiNTE1NjEzMTM1MTYzMjEiLCJmZiI6ImRmc2RzZGZzZGZzZHMiLCJuYmYiOjE1NTIyMTE4NjAsImV4cCI6MTU1MjIxMzY2MH0.
      3. 16m57YnnIcgIth25dwphQKPYuIq42BVmZV6LIBO7KDg

      它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT内部是没有换行的,这里只是为了便于展示,将它写成了几行。JWT 的三个部分依次如下。

      • Header(头部)
      • Payload(负载)
      • Signature(签名)

      简单讲下,Header描述加密算法与token类型,Payload描述的是实际需要传递的数据,如失效时间,签发人等等,Signature描述的是一段对于前面两部部分的签名,当然秘钥只有服务器才知道。

简单的介绍下JWT,更多的话,可以这边文章看看。我们着重讲下实现。

ASP.NET Core 的Middleware实现
  1. 创建JWT
    首先我们要先创建token,毕竟这个是最重要的。Core自带JWT帮助类,所以我们按照帮助类的意思来写个方法创建token。

    1. public string CreateJsonWebToken(Dictionary<string, string> payLoad)
    2. {
    3. if (string.IsNullOrWhiteSpace(setting.SecurityKey))
    4. {
    5. throw new ArgumentNullException("JsonWebTokenSetting.securityKey",
    6. "securityKey为NULL或空字符串。请在\"appsettings.json\"配置\"JsonWebToken\"节点及其子节点\"securityKey\"");
    7. }
    8. var now = DateTime.UtcNow;
    9. // Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims.
    10. // You can add other claims here, if you want:
    11. var claims = new List<Claim>();
    12. foreach (var key in payLoad.Keys)
    13. {
    14. var tempClaim = new Claim(key, payLoad[key]?.ToString());
    15. claims.Add(tempClaim);
    16. }
    17. // Create the JWT and write it to a string
    18. var jwt = new JwtSecurityToken(
    19. issuer: null,
    20. audience: null,
    21. claims: claims,
    22. notBefore: now,
    23. expires: now.Add(TimeSpan.FromMinutes(setting.ExpiresMinute)),
    24. signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(setting.SecurityKey)), SecurityAlgorithms.HmacSha256));
    25. var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
    26. return encodedJwt;
    27. }

    从方法我们看到,我们传入的是负载这个片段,而失效时间与秘钥我们是放在了appsettings.json来进行配置的。使用DI来获取配置文件中的节点值。

  2. 编写中间件
    我们都知道,中间件是Core的管道模型组成部分,所以我们在中间件做验证,来判断每次请求用户是有有权限是有该WebApi或者其他API。

    1. 中间件

      1. public JwtCustomerAuthorizeMiddleware(RequestDelegate next, IOptions<JsonWebTokenSetting> options, IJsonWebTokenValidate jsonWebTokenValidate, Func<Dictionary<string, string>, JsonWebTokenSetting, bool> validatePayLoad, List<string> anonymousPathList)
      2. {
      3. this._next = next;
      4. this._setting = options.Value;
      5. this._jsonWebTokenValidate = jsonWebTokenValidate;
      6. this._validatePayLoad = validatePayLoad;
      7. this._anonymousPathList = anonymousPathList;
      8. }
      9. public async Task Invoke(HttpContext context)
      10. {
      11. //JsonWebTokenValidate
      12. //若是路径可以匿名访问,直接跳过
      13. if (_anonymousPathList.Contains(context.Request.Path.Value))
      14. {
      15. //还未验证
      16. await _next(context);
      17. return;
      18. }
      19. var result = context.Request.Headers.TryGetValue("Authorization", out StringValues authStr);
      20. if (!result || string.IsNullOrEmpty(authStr.ToString()))
      21. {
      22. throw new UnauthorizedAccessException("未授权,请传递Header头的Authorization参数。");
      23. }
      24. //进行验证与自定义验证
      25. result = _jsonWebTokenValidate.Validate(authStr.ToString().Substring("Bearer ".Length).Trim()
      26. , _setting, _validatePayLoad);
      27. if (!result)
      28. {
      29. throw new UnauthorizedAccessException("验证失败,请查看传递的参数是否正确或是否有权限访问该地址。");
      30. }
      31. await _next(context);
      32. }

    从代码来看,anonymousPathList是URL路径,若是在这个List内的URL,便可直接跳过验证,
    接着将authStrtoken代入验证函数,validatePayLoad却是我们自代入的委托函数,用于服务器自定义验证。

    1. 验证
      验证方法,我只是做了签名验证与时间验证。并没有定得死死的,让用户自由度的去进行验证。

      1. public bool Validate(string encodeJwt, JsonWebTokenSetting setting, Func<Dictionary<string, string>, JsonWebTokenSetting, bool> validatePayLoad)
      2. {
      3. if (string.IsNullOrWhiteSpace(setting.SecurityKey))
      4. {
      5. throw new ArgumentNullException("JsonWebTokenSetting.securityKey",
      6. "securityKey为NULL或空字符串。请在\"appsettings.json\"配置\"JsonWebToken\"节点及其子节点\"securityKey\"");
      7. }
      8. var success = true;
      9. var jwtArr = encodeJwt.Split('.');
      10. var header = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[0]));
      11. var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[1]));
      12. var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(setting.SecurityKey));
      13. //首先验证签名是否正确(必须的)
      14. success = success && string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1])))));
      15. if (!success)
      16. {
      17. return success;//签名不正确直接返回
      18. }
      19. //其次验证是否在有效期内(也应该必须)
      20. var now = ToUnixEpochDate(DateTime.UtcNow);
      21. success = success && (now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString()));
      22. //再其次 进行自定义的验证
      23. success = success && validatePayLoad(payLoad, setting);
      24. return success;
      25. }
  3. 加载中间件

    1. 使用扩展方法,来封装中间件
    1. public static IApplicationBuilder UseJwtCustomerAuthorize(this IApplicationBuilder app, Action<IJwtCustomerAuthorezeOption> action)
    2. {
    3. var _JwtCustomerAuthorezeOption = app.ApplicationServices.GetService<IJwtCustomerAuthorezeOption>() as JwtCustomerAuthorezeOption; //new JwtCustomerAuthorezeOption();
    4. action(_JwtCustomerAuthorezeOption);
    5. return app.UseMiddleware<JwtCustomerAuthorizeMiddleware>(_JwtCustomerAuthorezeOption.validatePayLoad, _JwtCustomerAuthorezeOption.anonymousPath);
    6. }
    1. Startup.cs使用
    • 注册服务

      1. public void ConfigureServices(IServiceCollection services) {
      2. services.AddJwt(Configuration);}
    • 使用中间件
      1. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
      2. {
      3. app.UseJwtCustomerAuthorize(option =>
      4. {
      5. //设置不会被验证的url,可以使用链式调用一直添加
      6. option.SetAnonymousPaths(new System.Collections.Generic.List<string>()
      7. {
      8. // "/",
      9. "/Home/Privacy",
      10. "/Home/CreateJsonToken"
      11. });
      12. // 自定义验证函数,playLoad为带过来的参数字典,setting为失效时间与秘钥
      13. option.SetValidateFunc((playLoad, sertting) =>
      14. {
      15. return true;
      16. });
      17. });
      18. }

总结下,通过上面,就完成了JWT在ASP.NET Core使用中间件的方式的实现。简单来说就是用自带方法创建token,验证则使用中间件的形式,每次请求都需要进行验证当然你可以设置特殊URL。在下篇文章我们来讲讲使用策略模式的JWT实现。

JWT(JSON Web Token) 【转载】的更多相关文章

  1. Java JWT: JSON Web Token

    Java JWT: JSON Web Token for Java and Android JJWT aims to be the easiest to use and understand libr ...

  2. 如何在SpringBoot中集成JWT(JSON Web Token)鉴权

    这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...

  3. [更新]一份包含: 采用RSA JWT(Json Web Token, RSA加密)的OAUTH2.0,HTTP BASIC,本地数据库验证,Windows域验证,单点登录的Spring Security配置文件

    没有任何注释,表怪我(¬_¬) 更新: 2016.05.29: 将AuthorizationServer和ResourceServer分开配置 2016.05.29: Token获取采用Http Ba ...

  4. ( 转 ) 什么是 JWT -- JSON WEB TOKEN

    什么是JWT Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点 ...

  5. 关于JWT(Json Web Token)的思考及使用心得

    什么是JWT? JWT(Json Web Token)是一个开放的数据交换验证标准rfc7519(php 后端实现JWT认证方法一般用来做轻量级的API鉴权.由于许多API接口设计是遵循无状态的(比如 ...

  6. 什么是JWT(Json Web Token)

    什么是 JWT (Json Web Token) 用户认证是计算机安全领域一个永恒的热点话题. JWT 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519). 该to ...

  7. API安全验证之JWT(JSON WEB TOKEN) OLCMS

    假如www.olcms.com/getUserInfo获取用户信息,你怎么知道当前用户是谁?有人说登陆时候我把他UID写入session了,如果是API接口,没有session怎么办,那么就需要把UI ...

  8. 5分钟搞懂:JWT(Json Web Token)

    https://www.qikegu.com/easy-understanding/892 JWT 基于token的用户认证原理:让用户输入账号和密码,认证通过后获得一个token(令牌),在toke ...

  9. JWT(Json Web Token)认证

    目录 JWT(Json Web Token) JWT的数据结构 JWT的用法 JWT验证流程

随机推荐

  1. 修改hbuilder背景颜色为护眼模式

    复制以下代码,保存为.tmTheme文件导入HBuilder <?xml version="1.0" encoding="UTF-8"?> < ...

  2. linux下anaconda和keras配置过程

    连接服务器,使用ssh协议. 下载anaconda bash Anaconda3-5.1.0-Linux-x86_64.sh(安装过程需要输入yes来添加环境变量,需要输入一次安装路径.) 因为环境变 ...

  3. Qt 快捷键

  4. CRC8反转校验

    最近在做项目遇到一个问题,就是需要对数据进行CRC8校验,多项式是 X7+X6+X5+X2+1,对应的二进制表达是 11100101,但是因为传输反转所以我们这里的多项式二进制表达方式 为 10100 ...

  5. java第七周----json

    JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式.它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于 ...

  6. vue中使用ajax

    var vue = new Vue({ el:"#vueid", data:{ selectById : "", }, methods:{ yourMethod ...

  7. python学习-迭代器,列表解析和列表生成式

    迭代器为类序列对象提供了一个类序列的接口.Python 的迭代无缝的支持序列对象,而且还允许程序猿迭代非序列类型,包括用户定义的对象. 迭代器是一个next()方法的对象,而不是通过索引计数.当需要下 ...

  8. HTML语言发展史

    .发展时间线 1982年,Tim Berners-Lee 建立 HTML 1993年,大學生的 Marc Andreessen 在他的 Mosaic 浏览器加入 标记,从此可以在Web頁面上浏览图片 ...

  9. wpf binging (六)多绑定

    场景 比如我用四个textbox 需要每个控件都输入正确的数据以后 下方的 button才变成可用状态 需要把四个textbox的值转换成 true或者false 效果

  10. vs2017cpu占用过高解决方案

    最近在开发中,发现机器变得很卡顿.查看资源管理器发现vs的cpu使用率一直在20%-40%之间.占据了大量的系统计算资源. 展开资源管理器发现有很多node的线程,杀死后,他们又会自己起来! 一翻搜索 ...