我正在尝试通过构建三个组件然后组合它们来手动构建JWT令牌。根据这个:https://jwt.io/这个标记有三个部分; JWT标头,有效负载和签名。以下代码似乎成功生成了前两个。但签名不正确:
public async Task<string> GetJWTToken(string user)
{
var now = DateTime.UtcNow;
//constructing part 1: header.Encode()
JwtHeader jwtHeader = new JwtHeader();
jwtHeader.Add("alg", JwtAlgorithms.HMAC_SHA512);
var partOne = jwtHeader.Base64UrlEncode();
//constructing part 2: payload.Encode
JwtPayload payload = new JwtPayload();
payload.Add("sub", user);
payload.Add("nbf",ConvertToUnixTimestamp(now.AddMinutes(-10)));
var partTwo = payload.Base64UrlEncode();
//constructing part 3: HS512(part1 + "." + part2, key)
var tobeHashed = partOne + "." + partTwo;
var sha = new HMACSHA512(Encoding.UTF8.GetBytes(ConfigurationHelper.AppSettings("JWTOfferKey")));
var hashedByteArray = sha.ComputeHash(Encoding.UTF8.GetBytes(tobeHashed));
StringBuilder partThree = new StringBuilder();
foreach (var hashedByte in hashedByteArray)
{
partThree.Append(hashedByte.ToString("X2"));
}
//token = part1 + "." + part2 + "." + part3
var tokenString = partOne + "." + partTwo + "." + Base64Encode(partThree.ToString());
return tokenString;
}
public static double ConvertToUnixTimestamp(DateTime date)
{
DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
TimeSpan diff = date.ToUniversalTime() - origin;
return Math.Floor(diff.TotalSeconds);
}
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
有人知道最后一部分的构造有什么问题吗?
答案 0 :(得分:2)
最后一部分的构造有什么问题?
您需要base64UrlEncode签名哈希值
public Task<string> GetJWTToken(string user) {
//...other code removed for brevity
//constructing part 3: HS512(part1 + "." + part2, key)
var tobeHashed = string.Join(".", partOne, partTwo);
var sha = new HMACSHA512(Encoding.UTF8.GetBytes(ConfigurationHelper.AppSettings("JWTOfferKey")));
var hashedByteArray = sha.ComputeHash(Encoding.UTF8.GetBytes(tobeHashed));
//You need to base64UrlEncode the signature hash value
var partThree = Base64UrlEncode(hashedByteArray);
//Now construct the token
var tokenString = string.Join(".", tobeHashed, partThree);
//await was not used so no need for `async` keyword. Just return task
return Task.FromResult(tokenString);
}
// from JWT spec
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;
}