Я использую следующий код 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
Я немного не разбираюсь в этой проблеме. Может кто-то, пожалуйста, помогите мне отправиться в правильном направлении.
В версии 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
var jwt_enc_signature = $.base64.encode(sh_h256);