当前位置: 移动技术网 > IT编程>开发语言>.net > ASP.NET Core的JWT的实现(中间件).md

ASP.NET Core的JWT的实现(中间件).md

2019年03月18日  | 移动技术网IT编程  | 我要评论

司文痞子全集,垂头丧气的意思,儿歌mp3下载

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

 

 

引言:挺久没更新了,之前做了vue的系列,后面想做做服务端的系列,上下衔接,我们就讲讲webapi(网络应用程序接口),接口免不了用户认证,所以接下来我们的主题系列文章便是“ 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,更多的话,可以这边看看。我们着重讲下实现。

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.  
    7. // specifically add the jti (random nonce), iat (issued timestamp), and sub (subject/user) claims. 
    8. // you can add other claims here, if you want: 
    9. var claims = new list<claim>(); 
    10. foreach (var key in payload.keys) 
    11. var tempclaim = new claim(key, payload[key]?.tostring()); 
    12. claims.add(tempclaim); 
    13.  
    14. // create the jwt and write it to a string 
    15. var jwt = new jwtsecuritytoken( 
    16. issuer: null
    17. audience: null
    18. claims: claims, 
    19. notbefore: now, 
    20. expires: now.add(timespan.fromminutes(setting.expiresminute)), 
    21. signingcredentials: new signingcredentials(new symmetricsecuritykey(encoding.ascii.getbytes(setting.securitykey)), securityalgorithms.hmacsha256)); 
    22. var encodedjwt = new jwtsecuritytokenhandler().writetoken(jwt); 
    23. 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.  
      8. public async task invoke(httpcontext context) 
      9. //jsonwebtokenvalidate 
      10. //若是路径可以匿名访问,直接跳过 
      11. if (_anonymouspathlist.contains(context.request.path.value)) 
      12. //还未验证 
      13. await _next(context); 
      14. return
      15. var result = context.request.headers.trygetvalue("authorization", out stringvalues authstr); 
      16. if (!result || string.isnullorempty(authstr.tostring())) 
      17. throw new unauthorizedaccessexception("未授权,请传递header头的authorization参数。"); 
      18.  
      19. //进行验证与自定义验证 
      20. result = _jsonwebtokenvalidate.validate(authstr.tostring().substring("bearer ".length).trim() 
      21. , _setting, _validatepayload); 
      22. if (!result) 
      23. throw new unauthorizedaccessexception("验证失败,请查看传递的参数是否正确或是否有权限访问该地址。"); 
      24.  
      25. 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. <

        如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

      相关文章:

      验证码:
移动技术网