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. Beta冲刺前的准备

    Beta冲刺前准备 1.讨论组长否重选的议题和结论 经过团队讨论,不重选组长.我们团队在队长的带领下积极完成任务,使得团队项目初具模型.经过alpha阶段,我们的团队从一开始的零散到如今的凝聚,通力合 ...

  2. Python 元组tuple相关知识

    列表是有序的,列表元素可以被修改.元组是有序的,元组的一级元素不可被修改,但如果是元组的二级.三级元素并且刚好该元素是列表,则可以被修改.元组中的元组可进行for 循环,因此元组也是可迭代对象.字符串 ...

  3. Vue语法学习第四课(2)——class与style的绑定

    之前学到的指令 v-bind 在用于绑定class和style时,表达式结果可以是字符串.数组.对象. 一.绑定HTMLClass ① 对象语法 <div class="static& ...

  4. jQuery常用 遍历函数

    jQuery 遍历函数包括了用于筛选.查找和串联元素的方法.本文主要介绍日常工作中常用的JQ遍历,帮助一下初学者快速的接触遍历函数,提高自己的代码编写速度,写出更简洁更实用的代码,祝前端的同学们,在前 ...

  5. SQL Server-常用分页语句

    --SQL Server 2012及以上版本 , select field1, field2 from table1where 1=1 order by field1 offset @pageInde ...

  6. 第二次scrum冲刺

    一.第二次冲刺任务         Scrum是在已有的基础上实现读者查询书籍的功能. 二.用户故事         用户输入账号.密码   用户输入需要查询的书籍   系统显示用户输入的信息的详细信 ...

  7. windows下端口占用处理工具

    一.通用方法 经常,我们在启动应用的时候发现系统需要的端口被别的程序占用,笔者在最近使用tomcat时,老是会遇到这种端口占用的问题,如何知道谁占有了我们需要的端口,很多人都比较头疼,以下是通用方法: ...

  8. zt secureCRT serialNo

    Name: ygeR Company: TEAM ZWT SerialNumber: 03-77-119256 License Key: ABH2MJ 9YVAC5 Z17QF7 4ZAS7Z ABG ...

  9. 三,用户交互方式与python基本数据类型

    一.与用户交互 input python2中:用户输入什么类型的数据,就储存为什么类型的数据.比如输入数字则储存为整型,输入符号则存储为字符串型.raw_input会将所有输入的类型转换为字符串型. ...

  10. JavaScript Node节点笔记

    1. 节点及其类型: 1). 元素节点 2). 属性节点: 元素的属性, 可以直接通过属性的方式来操作. 3). 文本节点: 是元素节点的子节点, 其内容为文本. 2. 在 html 文档的什么位置编 ...