Токен JWT, сгенерированный из c #, не совпадает с Javascript

1

Я использую следующий код 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==

и я использую следующий код С# для создания того же токена:

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
    Попробуйте использовать base64urlencoding вместо base64: var jwt_enc_signature = $.base64.encode(sh_h256);
Теги:
jwt

1 ответ

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);

В С# вы делаете то же, что и в 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;
    }
}

что приводит к другой сигнатуре в двух версиях.

Как описано в https://jwt.io/introduction/

Вы должны создать подпись так же, как в своей JS-версии, и сделать base64Url-кодировку подписи, которая затем будет объединена с токеном.

Поэтому ваша версия JS выглядит корректно, но я не могу проверить токен на https://jwt.io

  • 0
    Привет jps Большое спасибо за ваше время и ответ. Это помогло мне исправить код c #, и теперь я могу успешно проверить сгенерированный токен на jwt.io. но это все еще не совпадает с кодом сценария Java. Похоже, некоторые проблемы с реализацией JS. Я буду смотреть и обновлять
  • 0
    Пожалуйста. Вам удалось исправить проблемы с js?
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню