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. Asp.net APP 重置密码的方式

    在开发ASP.NET WEB APP的时候,时间长了容易忘记最初设置的密码,即使打开数据库也不好重置,因为密码都是加密存储在数据库中的.下面是几种通过代码重置密码的方式: 第一种: string re ...

  2. 小程序 web-view 嵌套的网页跳转到小程序内部页面 实现无缝连接

    需要在H5页面被作出判断和处理  点击事件发生时跳转到小程序内部页面 1.引入小程序提供的JS <script type="text/javascript" src=&quo ...

  3. KendoUi 学习笔记(二) Grid

    Kendo.ui.Grid Kendo Ui Grid控件,继承至Widget. 一.构造       allowCopy    Boolen|Object  (默认:false) 当他设置true, ...

  4. MVC简单增删改

    /// <summary> /// /显示分页 /// </summary> /// <param name="model"></para ...

  5. git 合并分支到master

    git 合并分支到master   假如我们现在在dev分支上,刚开发完项目,执行了下列命令 git add .git commit -m ‘dev'git push -u origin dev 然后 ...

  6. centos7:ftp上传文件

    ftp> lcd /var/www/sss  上传文件的地址还一种上传方式ftp> passivePassive mode off.ftp> passivePassive mode ...

  7. better-scroll

    better-scroll会将默认事件阻止掉,如果自己写的部分需要有点击事件,需要在参数里加上click:true. 同时,在PC上或某些手机端,由于未成功将touchend事件move掉,点击事件会 ...

  8. cf A Simple Task---线段树

    Examples Input 10 5abacdabcda7 10 05 8 11 4 03 6 07 10 1 Output cbcaaaabdd Input 10 1agjucbvdfk1 10 ...

  9. redis学习步骤

    Redis简介 redis全称REmote DIctionary Server,是一个由Salvatore Sanfilippo写的高性能key-value存储系统,其完全开源免费,遵守BSD协议.R ...

  10. Exception in thread "main" java.lang.NullPointerException at Class.main

    出现这种问题,可能的原因之一可能是对象数组未初始化. Class[] class = new Class[N]; for(int i = 0; i < N; i++){ class[i] = n ...