数字 1 在 URL 编码后随机附加到我的 JWT 密钥的末尾



我已经搜索了每一个角落和缝隙,以寻找解决问题的方法,但我似乎找不到。

我有一个利用方法来创建JSON Web令牌的类。我创建的 Web 令牌需要匹配以下内容(请注意,我的密钥的最右侧没有数字 1):

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBrZXkiOiIxMjMtNDU2LTc4OS0wIiwicmVzb3VyY2UiOiJnZXRfZ2VvY29kZSJ9.xGLb92d6yVLqLf5TnrahMCxm-OGTHmXiXLvnRUqLWYM

我生成的令牌与上面的令牌匹配,除了在我的令牌的最右端随机附加了一个数字 1:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBrZXkiOiIxMjMtNDU2LTc4OS0wIiwicmVzb3VyY2UiOiJnZXRfZ2VvY29kZSJ9.xGLb92d6yVLqLf5TnrahMCxm-OGTHmXiXLvnRUqLWYM1

如您所见,这是 JWT 中保存机密的部分。让我演示一下如何生成和加密令牌,以便您可以帮助诊断问题。我将向您展示整个课程,然后引导您完成这些方法。

这是整个课程:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.Security.Cryptography;
namespace Project.JWT
{
public class Token
{
public string CreateToken(string resource, string appkey, string secret, string algorithm)
{
if (algorithm != "HS256")
return "Algorithm not supported";
JwtPayload payload = new JwtPayload
{
appkey = appkey,
resource = resource
};
return EncodeToken(payload, secret);
}
public static string EncodeToken(JwtPayload jwtPayload, string secret)
{
const string algorithm = "HS256";
var header = new Header
{
typ = "JWT",
alg = algorithm
};
var jwt = Base64Encode(JsonConvert.SerializeObject(header)) + "." + Base64Encode(JsonConvert.SerializeObject(jwtPayload));
jwt += "." + Sign(jwt, secret);
return jwt;
}

public static string Base64Encode(dynamic obj)
{
Type strType = obj.GetType();
var base64EncodedValue = Convert.ToBase64String(strType.Name.ToLower() == "string" ? Encoding.UTF8.GetBytes(obj) : obj);
return base64EncodedValue;
}

private static string Sign(string str, string key)
{

byte[] signature;
using (var crypto = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
{
signature = crypto.ComputeHash(Encoding.UTF8.GetBytes(str));
}
return System.Web.HttpServerUtility.UrlTokenEncode(signature);
}
}

public class Header
{
public string alg { get; set; }
public string typ { get; set; }
}
public class JwtPayload
{
public string appkey { get; set; }
public string resource { get; set; }
}

}

首先,向 CreateToken 方法传递用于创建有效负载的凭据。然后,它调用将有效负载和机密作为参数的 EncodeToken 方法。请记住,我的秘密是一个硬编码字符串,在应用程序的整个生命周期中永远不会更改;所以我知道这不是随机生成数字 1。

第 39 行,标头和有效负载被转换为 base 64 字符串,并通过一个点连接在一起,该点完美地生成了我的令牌的前两部分:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhcHBrZXkiOiIxMjMtNDU2LTc4OS0wIiwicmVzb3VyY2UiOiJnZXRfZ2VvY29kZSJ9

然后,我在第 41 行调用 Sign 方法,该方法使用 SHA256 算法请求对我的令牌进行签名。

Sign 方法接受组合的标头和有效负载作为 str,然后将机密作为密钥传递。

在第 62 行,我使用我的自定义密钥(即"testsecret")开始创建签名。

然后,我在返回签名之前对第 67 行的签名进行 URL 编码。当我返回它时,第 41 行将令牌的三个部分组合在一起,从而给我留下了一个完美的 JWT......除了秘密最右端的数字"1"。

请帮忙。

这与 HttpServerUtility.UrlTokenEncode 的工作方式有关,强调我的:

使用基数 64 位将字节数组编码为其等效的字符串表示形式,可用于在 URL 上传输

您将知道,根据其长度,Base64 字符串将填充并附加=末尾。=不被视为 URL 安全,因此替换为表示计数的整数,在本例中为1

您可以通过调试并替换下面的行来测试这一点...

return System.Web.HttpServerUtility.UrlTokenEncode(signature);

。有了这个...

return Convert.ToBase64String(signature);

。并检查返回值。

您将看到它以=结尾,因此HttpServerUtility.UrlTokenEncode将其替换为1

最新更新