既然选择了远方,便只顾风雨兼程 __ HANS许

引言:挺久没更新了,之前做了Vue的系列,后面想做做服务端的系列,上下衔接,我们就讲讲WebApi(网络应用程序接口),接口免不了用户认证,所以接下来我们的主题系列文章便是“基于ASP.NET Core的用户认证”,分为市面上流行的JWT(JSON WebToken)与OAuth2(开放授权)

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. "到期时间": "2018年7月1日0点0分" 



    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. if (string.IsNullOrWhiteSpace(setting.SecurityKey)) 



    3. throw new ArgumentNullException("JsonWebTokenSetting.securityKey", 

    4. "securityKey为NULL或空字符串。请在\"appsettings.json\"配置\"JsonWebToken\"节点及其子节点\"securityKey\""); 



    5. var now = DateTime.UtcNow; 


    6. // Specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims. 

    7. // You can add other claims here, if you want: 

    8. var claims = new List<Claim>(); 

    9. foreach (var key in payLoad.Keys) 



    10. var tempClaim = new Claim(key, payLoad[key]?.ToString()); 

    11. claims.Add(tempClaim); 




    12. // Create the JWT and write it to a string 

    13. var jwt = new JwtSecurityToken( 

    14. issuer: null, 

    15. audience: null, 

    16. claims: claims, 

    17. notBefore: now, 

    18. expires: now.Add(TimeSpan.FromMinutes(setting.ExpiresMinute)), 

    19. signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(setting.SecurityKey)), SecurityAlgorithms.HmacSha256)); 

    20. var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt); 

    21. return encodedJwt; 



    从方法我们看到,我们传入的是负载这个片段,而失效时间与秘钥我们是放在了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. this._next = next; 

      3. this._setting = options.Value; 

      4. this._jsonWebTokenValidate = jsonWebTokenValidate; 

      5. this._validatePayLoad = validatePayLoad; 

      6. this._anonymousPathList = anonymousPathList; 




      7. public async Task Invoke(HttpContext context) 



      8. //JsonWebTokenValidate 

      9. //若是路径可以匿名访问,直接跳过 

      10. if (_anonymousPathList.Contains(context.Request.Path.Value)) 



      11. //还未验证 

      12. await _next(context); 

      13. return; 



      14. var result = context.Request.Headers.TryGetValue("Authorization", out StringValues authStr); 

      15. if (!result || string.IsNullOrEmpty(authStr.ToString())) 



      16. throw new UnauthorizedAccessException("未授权,请传递Header头的Authorization参数。"); 




      17. //进行验证与自定义验证 

      18. result = _jsonWebTokenValidate.Validate(authStr.ToString().Substring("Bearer ".Length).Trim() 

      19. , _setting, _validatePayLoad); 

      20. if (!result) 



      21. throw new UnauthorizedAccessException("验证失败,请查看传递的参数是否正确或是否有权限访问该地址。"); 




      22. await _next(context); 



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

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

      1. public bool Validate(string encodeJwt, JsonWebTokenSetting setting, Func<Dictionary<string, string>, JsonWebTokenSetting, bool> validatePayLoad) 



      2. if (string.IsNullOrWhiteSpace(setting.SecurityKey)) 



      3. throw new ArgumentNullException("JsonWebTokenSetting.securityKey", 

      4. "securityKey为NULL或空字符串。请在\"appsettings.json\"配置\"JsonWebToken\"节点及其子节点\"securityKey\""); 




      5. var success = true; 

      6. var jwtArr = encodeJwt.Split('.'); 

      7. var header = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[0])); 

      8. var payLoad = JsonConvert.DeserializeObject<Dictionary<string, string>>(Base64UrlEncoder.Decode(jwtArr[1])); 


      9. var hs256 = new HMACSHA256(Encoding.ASCII.GetBytes(setting.SecurityKey)); 

      10. //首先验证签名是否正确(必须的) 

      11. success = success && string.Equals(jwtArr[2], Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1]))))); 

      12. if (!success) 



      13. return success;//签名不正确直接返回 



      14. //其次验证是否在有效期内(也应该必须) 

      15. var now = ToUnixEpochDate(DateTime.UtcNow); 

      16. success = success && (now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString())); 


      17. //再其次 进行自定义的验证 

      18. success = success && validatePayLoad(payLoad, setting); 


      19. return success; 



  3. 加载中间件

    1. 使用扩展方法,来封装中间件
    1. public static IApplicationBuilder UseJwtCustomerAuthorize(this IApplicationBuilder app, Action<IJwtCustomerAuthorezeOption> action) 



    2. var _JwtCustomerAuthorezeOption = app.ApplicationServices.GetService<IJwtCustomerAuthorezeOption>() as JwtCustomerAuthorezeOption; //new JwtCustomerAuthorezeOption(); 

    3. action(_JwtCustomerAuthorezeOption); 

    4. return app.UseMiddleware<JwtCustomerAuthorizeMiddleware>(_JwtCustomerAuthorezeOption.validatePayLoad, _JwtCustomerAuthorezeOption.anonymousPath); 



    1. Startup.cs使用
    • 注册服务

      1. public void ConfigureServices(IServiceCollection services) { 

      2. services.AddJwt(Configuration);} 

    • 使用中间件
      1. public void Configure(IApplicationBuilder app, IHostingEnvironment env) 



      2. app.UseJwtCustomerAuthorize(option => 



      3. //设置不会被验证的url,可以使用链式调用一直添加 

      4. option.SetAnonymousPaths(new System.Collections.Generic.List<string>() 



      5. // "/", 

      6. "/Home/Privacy", 

      7. "/Home/CreateJsonToken" 

      8. }); 

      9. // 自定义验证函数,playLoad为带过来的参数字典,setting为失效时间与秘钥 

      10. option.SetValidateFunc((playLoad, sertting) => 



      11. return true; 

      12. }); 

      13. }); 

      14. }  

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

ASP.NET Core的JWT的实现(中间件).md的更多相关文章

  1. ASP.NET Core 基于JWT的认证(二)

    ASP.NET Core 基于JWT的认证(二) 上一节我们对 Jwt 的一些基础知识进行了一个简单的介绍,这一节我们将详细的讲解,本次我们将详细的介绍一下 Jwt在 .Net Core 上的实际运用 ...

  2. ASP.NET Core的JWT的实现(自定义策略形式验证).md

    既然选择了远方,便只顾风雨兼程 __ HANS许 在上篇文章,我们讲了JWT在ASP.NET Core的实现,基于中间件来实现.这种方式有个缺点,就是所有的URL,要嘛需要验证,要嘛不需要验证,没有办 ...

  3. Asp.Net Core基于JWT认证的数据接口网关Demo

    近日,应一位朋友的邀请写了个Asp.Net Core基于JWT认证的数据接口网关Demo.朋友自己开了个公司,接到的一个升级项目,客户要求用Aps.Net Core做数据网关服务且基于JWT认证实现对 ...

  4. asp.net core 集成JWT(二)token的强制失效,基于策略模式细化api权限

    [前言] 上一篇我们介绍了什么是JWT,以及如何在asp.net core api项目中集成JWT权限认证.传送门:https://www.cnblogs.com/7tiny/p/11012035.h ...

  5. ASP.NET Core 基于JWT的认证(一)

    ASP.NET Core 基于JWT的认证(一) Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计 ...

  6. asp.net core 集成JWT(一)

    [什么是JWT] JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案. JWT的官网地址:https://jwt.io/ 通俗地来讲,JWT是能代表用户身份的令牌,可以使用JWT ...

  7. Asp.Net Core 第06局:中间件

    总目录 前言 本文介绍Asp.Net Core 中间件. 环境 1.Visual Studio 2017 2.Asp.Net Core 2.2 开局 第一手:中间件概述     1.中间件:添加到应用 ...

  8. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  9. [转]ASP.NET Core 中的那些认证中间件及一些重要知识点

    本文转自:http://www.qingruanit.net/c_all/article_6645.html 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系 ...

随机推荐

  1. CSS3 之 童年的纸飞机

    今天我们来折纸飞机(可以飞出去的那种哦) 基本全用css来实现,只有一小部分的js 首先看一下飞机的构造 灰色区域为可折叠区域 白色区域为机身 三角形由border画出来的再经过各种平移翻转变成上图 ...

  2. Logistic回归(逻辑回归)和softmax回归

    一.Logistic回归 Logistic回归(Logistic Regression,简称LR)是一种常用的处理二类分类问题的模型. 在二类分类问题中,把因变量y可能属于的两个类分别称为负类和正类, ...

  3. 负载,性能测试工具-Gatling

    前言 Gatling Gatling是一款功能强大的负载测试工具,它为易于使用,高可维护性和高性能而设计. 开箱即用,Gatling由于对HTTP协议的出色支持,使其成为负载测试任何HTTP服务器的首 ...

  4. 微服务框架surging学习之路——序列化

    1.对微服务的理解 之前看到在群里的朋友门都在讨论微服务,看到他们的讨论,我也有了一些自己的理解,所谓微服务就是系统里的每个服务都 可以自由组合.自由组合这个就很厉害了,这样一来,每个服务与服务之间基 ...

  5. C# 设置Excel数据自适应行高、列宽的2种情况

    Excel表格中,由于各种数据的复杂性,可能存在单元格中的数据字号大小.数据内容长度不一而出现,列宽过宽.过窄或者行高过大.过小的问题.常见的解决方法是调整行高.列宽.在Microsoft Excel ...

  6. A项目轶事之加入项目2个月

    A项目轶事之加入项目2个月 4月18号是我入A项目整整2个月的日子. 加入项目第一天,就发现A项目是一个大规模的SAP ERP项目. SAP各大模块,Salesforce, MES等各个系统相关的顾问 ...

  7. Android 启动优化

    对与Android的项目来说,app的启动速度是非常重要的.因为用户打开你的app给别人的第一体验就是打开软件的速度.但是app的启动速度是比较难以缩短的,因为一般来说开发者在app的启动入口都会创建 ...

  8. Android之Material Dialogs详解

    文章大纲 一.什么是Material Dialogs二.Material Dialogs实战三.项目源码下载   一.什么是Material Dialogs   Material Dialogs是一个 ...

  9. 003-005:Java平台相关的面试题

    本文首发于公众号:javaadu 003:字节码是什么? 在Java中,字节码存放于以.class结尾的二进制文件. 字节码之于Java,类似于汇编语言之于C/C++.对于C/C++语言来说,不同的平 ...

  10. 记一次mongodb聚合查询

    先说一下场景,产品中用到了简单的表单构造器,开始提供了一系列的控件,例如单行文本框.多行文本框.单选.复选.时间等,之后你可以拖拽控件自己组装你想要的表单……网上有很多的表单构造器,这里就不细说了,可 ...