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. Linux Network Command

    查看 内外网访问ipnetstat -an download file from server scp -r root@139.xxx.xxx.82:~/virtualbox.box /tmp/

  2. TCP聊天工具的实现

    由于本人天生愚钝,所以关于聊天工具的编程一直都没学会,尽管网上教程一大堆,但是关于IdTCPClient  IdTCPServer 的不多,今天终于学会一些,分享给像我一样纠结的小伙伴,下一步学习多线 ...

  3. 使用 navicat 导入导出数据库

    1.使用 navicat 导出数据库 2.使用 navicat 导入数据库导入之前需要先建好数据库 3.可以直接使用navicat 到数据传输功能直接将一个数库copy到另一个数据库

  4. python flask 如何修改默认端口号

    场景:按照github文档上启动一个flask的app,默认是用5000端口,如果5000端口被占用,启动失败. 样例代码: from flask import Flask app = Flask(_ ...

  5. C#设计模式——单例模式的实现

    1. 什么是单例 保证一个类只有一个实例的实现方法. 2. 使用场景 页面访问计数器 需要保持状态的工具类 需求很多,不能一一列举了 3. 实现方 非线程安全 /// <summary> ...

  6. fdisk -l查看硬盘分区信息及硬盘分区介绍

    原文:https://blog.csdn.net/a1809032425/article/details/79692035 linux fdisk 命令和df区别是什么? fdisk工具是分区工具:d ...

  7. Keil的断点调试问题解决

    keil只有在程序能正常运行时才能添加断点后在点击调试任务时,断点标记不消失

  8. MAC Homebrew安装和简单使用

    前言: 这个周六日在刚刚买的macbookpro(系统版本是:10.13.5)上面安装angular,一开始是按照windows上的顺序安装的,先安装node.js,然后在安装angular的时候报错 ...

  9. VB Mouse Pointer

  10. Python面面面

    1:Python有哪些特点和优点? 作为一门编程入门语言,Python主要有以下特点和优点: 可解释 具有动态特性 面向对象 简明简单 开源 具有强大的社区支持 当然,实际上Python的优点远不止如 ...