从c#生成的JWT令牌与Javascript

时间:2017-07-27 13:15:13

标签: javascript c# jwt

我使用以下java脚本代码生成jwt令牌:

<head>
    <meta charset="utf-8" />
    <script src="js/jquery-1.11.3.min.js"></script>
    <script src="js/jquery.base64.js"></script>
    <script src="js/aes.js"></script>
    <script src="js/aes-json-format.js"></script>
    <script src="js/hmac.js"></script>
    <script src="js/sha256.js"></script>

    <title>Cryptography</title>
</head>

<body>
   <div>
     <div id="jwtToken" style="font:14px bold;  word-wrap: break-word;" />
   </div>
   <script type="text/javascript">
    $(document).ready(function(e){
      var data = {
        user_type: "tmr",
        user_id: "OFhMQVZaS1l0SVFQNGtyaUpoOWRodz09",
        accesstoken: "F4111553-802B-B45C-F8DB-627D5933691E"
      }
      var payload  = {
        "iat": 101,
        "nbf":101,
        "exp":161,
        "iss":"offers/index",
        "jti":'',
        "data": data
      };
      var secret_key = "pa@987";
      var n_header = {alg:"HS256",typ:"JWT"};

      var enc_header = $.base64.encode(JSON.stringify(n_header));
      var enc_payload =$.base64.encode(JSON.stringify(payload));

      console.log("---- encrypted header---")
      console.log(enc_header);
      console.log("---- encrypted payload---")
      console.log(payload);

      var token = enc_header + "." + enc_payload;

      var sh_h256 = CryptoJS.HmacSHA256(token, secret_key);
      var jwt_enc_signature = $.base64.encode(sh_h256);

      token = token + "." + jwt_enc_signature;

      console.log("---- JWT  Signature ---");
      console.log(jwt_enc_signature);

      console.log("----- JWT Token ------");
      console.log(token);

      document.getElementById('jwtToken').innerHTML = token;
    });
    </script>
</body>

上面的代码让我得到以下标记:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjEwMSwibmJmIjoxMDEsImV4cCI6MTYxLCJpc3MiOiJvZmZlcnMvaW5kZXgiLCJqdGkiOiIiLCJkYXRhIjp7InVzZXJfdHlwZSI6InRtciIsInVzZXJfaWQiOiJPRmhNUVZaYVMxbDBTVkZRTkd0eWFVcG9PV1JvZHowOSIsImFjY2Vzc3Rva2VuIjoiRjQxMTE1NTMtODAyQi1CNDVDLUY4REItNjI3RDU5MzM2OTFFIn19.YjdlNTcxMTliNGM0OTA2ZTVmYzY2NTlkZmQ1ZTk3YmQ0NDk4MGJmZGI3YzZlZjUzNGZmZTk3YmRmYjAwNmUyZA==

我正在使用以下c#代码生成相同的令牌:

static void test()
{
    dynamic data = new System.Dynamic.ExpandoObject();
    data.user_type = "tmr";
    data.user_id = "OFhMQVZaS1l0SVFQNGtyaUpoOWRodz09";
    data.accesstoken = "F4111553-802B-B45C-F8DB-627D5933691E";

    Object payload = new Dictionary<string, object>()
    {
        { "iat", 101 },
        { "nbf", 101 },
        { "exp", 161 },
        { "iss", "offers/index" },
        { "jti", "" },
        { "data", data }
    };

    var secret_key = "pa@987";

    dynamic n_header = new System.Dynamic.ExpandoObject();
    n_header.alg = "HS256";
    n_header.typ = "JWT";

    byte[] headerBytes = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(n_header));
    byte[] payloadBytes = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(payload));

    var enc_header = Base64UrlEncode(headerBytes);
    var enc_payload = Base64UrlEncode(payloadBytes);

    var token = enc_header + "." + enc_payload;

    var sh_h256 = JsonWebTokenConvert.Converter.CreateToken(token, secret_key);
    var jwt_enc_signature = Base64UrlEncode(sh_h256);

    token = token + "." + jwt_enc_signature;

    Console.WriteLine(token);
}

private static string Base64UrlEncode(byte[] input)
{
    var output = Convert.ToBase64String(input);
    output = output.Split('=')[0]; // Remove any trailing '='s
    output = output.Replace('+', '-'); // 62nd char of encoding
    output = output.Replace('/', '_'); // 63rd char of encoding
    return output;
}

public static byte[] CreateToken(string message, string secret)
{
    secret = secret ?? "";
    var encoding = new System.Text.ASCIIEncoding();
    byte[] keyByte = encoding.GetBytes(secret);
    byte[] messageBytes = encoding.GetBytes(message);
    string base64Message = Convert.ToBase64String(messageBytes);
    byte[] base64Bytes = encoding.GetBytes(base64Message);

    using (var hmacsha256 = new HMACSHA256(keyByte))
    {
        byte[] hashmessage = hmacsha256.ComputeHash(base64Bytes);
        return hashmessage;
    }
}

这让我跟随的标记与从java脚本代码生成的标记不匹配:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjEwMSwibmJmIjoxMDEsImV4cCI6MTYxLCJpc3MiOiJvZmZlcnMvaW5kZXgiLCJqdGkiOiIiLCJkYXRhIjp7InVzZXJfdHlwZSI6InRtciIsInVzZXJfaWQiOiJPRmhNUVZaYVMxbDBTVkZRTkd0eWFVcG9PV1JvZHowOSIsImFjY2Vzc3Rva2VuIjoiRjQxMTE1NTMtODAyQi1CNDVDLUY4REItNjI3RDU5MzM2OTFFIn19.EZtxFXJTwDExZFJuRcPppmY7d97MsUcfpxq1JI1VSBw

我对此问题毫无头绪。有人可以帮助我朝正确的方向前进。

1 个答案:

答案 0 :(得分:0)

在JavaScript版本中,您对标头和有效负载执行Base64编码,并将其作为字符串放在一起:

var enc_header = $.base64.encode(JSON.stringify(n_header));
var enc_payload =$.base64.encode(JSON.stringify(payload));
var token = enc_header + "." + enc_payload;

然后计算密钥并对其执行base64编码:

var sh_h256 = CryptoJS.HmacSHA256(token, secret_key);
var jwt_enc_signature = $.base64.encode(sh_h256);

在C#中,您在创建签名之前执行与JS相同的操作:

var enc_header = Base64UrlEncode(headerBytes);
var enc_payload = Base64UrlEncode(payloadBytes);
var token = enc_header + "." + enc_payload;

但不是加密令牌,而是调用CreateToken

var sh_h256 = JsonWebTokenConvert.Converter.CreateToken(token, secret_key);

但遗憾的是,您的CreateToken函数在计算签名之前再次对消息进行base64编码:

public static byte[] CreateToken(string message, string secret)
{
    ...
    string base64Message = Convert.ToBase64String(messageBytes);
    ...
    using (var hmacsha256 = new HMACSHA256(keyByte))
    {
        byte[] hashmessage = hmacsha256.ComputeHash(base64Bytes);
        return hashmessage;
    }
}

导致两个版本中的签名不同。

正如config helper

所述

您必须像在JS版本和签名的do base64Url编码中那样创建签名,然后将其连接到令牌。

所以你的JS版本看起来是正确的,但我无法在https://jwt.io/introduction/

上验证令牌