zoukankan      html  css  js  c++  java
  • JWT

     

    JWT是什么?

    JWT全称是Json Web Token,是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准( RFC 7519 ),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

    JWT的结构

    JWT一般由三段构成,用.号分隔开,第一段是header,第二段是payload,第三段是signature,例如:

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiTXJCdWciLCJleHAiOjE1MTI5NTkzMDMuMCwianRpIjoibHVvemhpcGVuZyJ9.9iwGMHmS0mophyFgliLK15hs_eE770IchaZ-bWcX5c0

    1header

    jwt的头部承载两部分信息:

    声明类型。这里是jwt
    声明加密的算法。通常直接使用 HMAC SHA256,其它还有RS256

    完整的头部就像下面这样的JSON

      {

    "alg": "HS256",

     "typ": "JWT"

    }

     然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 

    2playload

    载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分:

      标准中注册的声明
      公共的声明
      私有的声明

    标准中注册的声明 (建议但不强制使用)

        iss jwt签发者
        subjwt所面向的用户
        aud:接收jwt的一方
        expjwt的过期时间,这个过期时间必须要大于签发时间
        nbf:定义在什么时间之前,该jwt都是不可用的.
        iat jwt的签发时间
        jti  jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

     

    公共的声明
    公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

    私有的声明
    私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

    定义一个playload

    {

        "name": "MrBug",

        "exp": 1512959303,

        "jti": "luozhipeng"

    }

     然后将其进行base64加密,得到Jwt的第二部分

    eyJuYW1lIjoiTXJCdWciLCJleHAiOjE1MTI5NTkzMDMuMCwianRpIjoibHVvemhpcGVuZyJ9 

     

    3signature

    jwt的第三部分是一个签证信息,这个签证信息由三部分组成:

        header (base64后的)
        payload (base64后的)
        secret

    这个部分需要base64加密后的headerbase64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加secret组合加密,然后就构成了jwt的第三部分。

    var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);

    var signature = HMACSHA256(encodedString, 'secret');

    9iwGMHmS0mophyFgliLK15hs_eE770IchaZ-bWcX5c0

    将这三部分用.连接成一个完整的字符串,构成了最终的jwt

    1

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiTXJCdWciLCJleHAiOjE1MTI5NTkzMDMuMCwianRpIjoibHVvemhpcGVuZyJ9.9iwGMHmS0mophyFgliLK15hs_eE770IchaZ-bWcX5c0

     
    注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

     

    整个流程就是这样的:

     

     

    安全相关

    不应该在jwtpayload部分存放敏感信息,因为该部分是客户端可解密的部分。

    保护好secret私钥,该私钥非常重要。

    如果可以,请使用https协议

    为什么要用JWT?

    一般在一个Web应用程序中,那么它通常使用一个cookie来表示一个已经登录的用户。一般的流程是:用户单击登录,进入登录页面,输入有效凭证后,服务器发送给用户浏览器的响应包含一个带有加密信息的Set-Cookie头。

    cookie会被设置上domain 例如 xxx.com,每次浏览器向这个domain发送请求时,设置在这个domain上的cookie也会被带上。在服务器上,cookie将被解密,然后使用解密后的内容来创建用户的Identity。

    如果客户端是一个浏览器,这种方式将会非常非常适合。不过当我们的客户端是一个移动应用程序时候,cookie机制将不再适用,所以我们要使用一种token机制来进行身份的认证,这里我们就可以使用JWT,优点如下:

    1.跨语言使用。

    2.服务器端无需再保存任何东西,只需要客户端保存token就可以。

    3.实现简单。

    4.统一认证方式,如果是移动端也要验证的话,jwt也支持就无需修改,否则客户端 服务器一套,移动端 服务器又是一套

    NET中JWT怎么用

    Nuget安装

     /// <summary>

     /// 获取token信息

     /// </summary>

     /// <param name="tokenModel"></param>

    /// <returns></returns>

    public static string issueJwt(TokenModel tokenModel)

    {

    //获取Appsetting配置信息

    string iss = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });

     string aud = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" });

     string secret = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });

     

     

    //构造payload

    var claims = new List<Claim>

    {
    //nbf 生效时间 、Jti 编号、iat 签发时间、aud 受众、exp 过期时间

    new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()),

    new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),

    new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,

     //这个就是过期时间,目前是过期1000秒,可自定义,注意JWT有自己的缓冲过期时间

    new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds()}"),

    new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(1000).ToString()),

    new Claim(JwtRegisteredClaimNames.Iss,iss),

    new Claim(JwtRegisteredClaimNames.Aud,aud),

    };

     

     

    //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)

     var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));

    //加密方式

    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

     

    var jwt = new JwtSecurityToken(

                issuer: iss,

                claims: claims,

                signingCredentials: creds);

     

    //生成jwt token

    var jwtHandler = new JwtSecurityTokenHandler();

    var encodedJwt = jwtHandler.WriteToken(jwt);

     

    return encodedJwt;

    }

     

    /// <summary>

    /// 解析

    /// </summary>

    /// <param name="jwtStr"></param>

    /// <returns></returns>

    public static TokenModel SerializeJwt(string jwtStr)

    {

    var jwtHandler = new JwtSecurityTokenHandler();

    JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);

    object role;

     try

    {

    jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);

    }

    catch (Exception e)

    {

    Console.WriteLine(e);

      throw;

    }

    var tm = new TokenModel

    {

         Uid = jwtToken.Id.ToString(),

         Role = role != null ? role.ToString() : "",

    };

     return tm;

    }

    }

    参考:

    https://blog.csdn.net/sd7o95o/article/details/78852450

    https://www.cnblogs.com/mrbug/p/8022826.html

    https://www.jianshu.com/p/2342260c95ff

    https://www.cnblogs.com/xiaojinFat/p/13345685.html

  • 相关阅读:
    linux学习(一)
    Linux学习(用户管理)
    anyproxy mac安装
    python mitmproxy 代理
    Js常用方法map, sort
    echarts常用配置项【持续更新】
    【转】moment js 使用
    js Cannot assign to read only property 'exports' of object '#<Object>' at Modul,import 与module.exports混用问题
    a标签跳转referer漏洞
    element ui rate评分组建使用
  • 原文地址:https://www.cnblogs.com/zxking/p/13396937.html
Copyright © 2011-2022 走看看