JSON jwt.io 上无法解码的 Web 令牌:"JWT payload is not a valid JSON object"
JSON Web Tokens Not Decodable on jwt.io: "JWT payload is not a valid JSON object"
使用下面的代码,我能够构建一个解码的 JSON Web 令牌 (decodedToken
)。当我将其粘贴到 https://jwt.io 上的调试器时,header 和有效负载正确显示在右侧。但是当我将编码的令牌 (encodedToken
) 粘贴到调试器中时,我收到此消息:
Looks like your JWT payload is not a valid JSON object. JWT payloads must be top level JSON objects as per https://www.rfc-editor.org/rfc/rfc7519#section-7.2
它还在底部用大红色字母表示“无效签名”。
此外,当使用编码令牌时,header区域显示我的解码header,有效负载区域显示我的整个解码令牌。所以 jwt.io 以某种方式成功解码了 JWT。但它不应该试图将整个解码令牌的 JSON 解析为一个单元。它应该尝试分别解析 header 的 JSON 和有效载荷部分。
我想知道为什么 jwt.io 不能完全满足我的编码令牌的有效负载。 decodedToken
和 encodedToken
的值在下面的源代码中显示为注释。谢谢。
private static string GetEncodedToken(string privateKey)
{
JObject header = JObject.FromObject(new { alg = "ES384", typ = "JWT" });
JObject payload = JObject.FromObject(new { name = "value" });//simple test JSON data
string decodedToken = Base64URLEncode(header) + "." + Base64URLEncode(payload);
//eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidmFsdWUifQ
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
using (ECDsa ecdsa = ECDsa.Create())
{
ecdsa.ImportECPrivateKey(privateKeyBytes, out _);
string encodedToken = JWT.Encode(decodedToken, ecdsa, JwsAlgorithm.ES384);
//eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ZXlKaGJHY2lPaUpGVXpNNE5DSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnVZVzFsSWpvaWRtRnNkV1VpZlE.kYj0M2GNC5w9oRrIVcHJ9dSQLbOEjNjxd61zSXD5iz0nBRRWMWyxj2l1DAhKPa_hpaFUscuubCzYe_W1SKpo3s06on-hYnICgQH4fVoAwZxiM_N4W761jecOExfivztn
return encodedToken;
}
}
private static string Base64URLEncode(JObject jObject)
{
string jsonString = jObject.ToString(Formatting.None);
byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonString);
string escapedBase64 = Convert.ToBase64String(jsonBytes).TrimEnd('=').Replace('+', '-').Replace('/', '_');
return escapedBase64;
}
更新
感谢您到目前为止的回答。我想我已经接近了,但是 jwt.io 仍然说“签名无效”,即使我已经粘贴了 public 密钥。使用以下信息,我希望有人能告诉我为什么我的签名被认为是无效的。
为了在 whosebug.com 上调试这种情况,我生成了一个临时私钥:
MIGkAgEBBDBywQ7LVcyOGzxJ0Tpjpww2zUZbbtb3WVm4A3uv7ho31jJzQRYTpSqR7+ORAdoxmamgBwYFK4EEACKhZANiAASG50vW1r/O1XmUbTBb6yx1YSABh1USA6MJ8HJnYJ58tjGGVPL88a6Z1gOUlAsHtNhL44PhnTNTNNFdaH2Z41yn7oZmBhuon0vuUNFic2HDpfa/uFwRUAmhSBQz8hu+980=
我用我的私钥初始化了一个 ecdsa
的实例,并用 Convert.ToBase64String(ecdsa.ExportSubjectPublicKeyInfo())
生成了一个 public 密钥:
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEhudL1ta/ztV5lG0wW+ssdWEgAYdVEgOjCfByZ2CefLYxhlTy/PGumdYDlJQLB7TYS+OD4Z0zUzTRXWh9meNcp+6GZgYbqJ9L7lDRYnNhw6X2v7hcEVAJoUgUM/IbvvfN
这是更新后的代码:
private static string GetSignedEncodedToken(string privateKey)
{
JObject payload = JObject.FromObject(new { name = "value" });//simple test JSON data
string payloadString = payload.ToString(Formatting.None);
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
using (ECDsa ecdsa = ECDsa.Create())
{
ecdsa.ImportECPrivateKey(privateKeyBytes, out _);
string signedEncodedToken = JWT.Encode(payloadString, ecdsa, JwsAlgorithm.ES384);
return signedEncodedToken;
}
}
这是签名的编码令牌:eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ew0KICAibmFtZSI6ICJ2YWx1ZSINCn0.KpJAgc3-yaoGmHGAXHOeH3BPgpxdBRm461yWia60dgjuQHG5iLnwLQtQgdZtsHnI-bEK_wdmvu85ZrF7n-TdWiFb4FQxGeLBeeRfnMLJhKfInu_7MYEWPS2Ohm4yBAqg
更新解决方案
正如 jps 所提到的,我需要用“-----BEGIN PUBLIC KEY-----”和“-----END PUBLIC 键-----”。然后 jwt.io 显示“签名已验证”。
这里所说的decodedToken
基本上已经是没有签名的编码令牌了。函数 JWT.Encode
采用第一个参数并重复您已经手动执行的操作,即它为您创建一个 base64url 编码的 header 和有效负载,然后对令牌进行签名。您不需要创建自己的 header,也不需要关心 base64url 编码。
因此您只需要将您的 payload
(不是 base64 编码)传递到那里。结果是一个签名的令牌。
并且 jwt.io 显示“无效签名”,因为您可能没有将 public 密钥传递给右栏中的“public 密钥”字段。不知道 public 密钥,无法验证签名。
当您在此处粘贴 public 键时,确保它有 header 和页脚行 -----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
,然后验证应该可以正常工作。
您提供的令牌,我在 jwt.io
调试器中使用了相同的令牌并且可以看到几个问题:
eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ZXlKaGJHY2lPaUpGVXpNNE5DSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnVZVzFsSWpvaWRtRnNkV1VpZlE.kYj0M2GNC5w9oRrIVcHJ9dSQLbOEjNjxd61zSXD5iz0nBRRWMWyxj2l1DAhKPa_hpaFUscuubCzYe_W1SKpo3s06on-hYnICgQH4fVoAwZxiM_N4W761jecOExfivztn
解码详情如下:
Header (which is correct):
{
"alg": "ES384",
"typ": "JWT"
}
Payload (which is not correct):
"eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidmFsdWUifQ"
因为有效负载应该是 Json,而不是 Base64Encoded
字符串。您应该能够修改它以生成新的令牌。
Now Main Error:
解码调试器肯定需要Public密钥,它可以与私钥匹配,如果你使用非对称加密,如果你使用Symmetric encryption
那么两个密钥将是相同的。
您还可以选择添加私钥以生成具有修改算法或负载的新令牌。
Programmatically you are able to see the details:
- 您正在提供正确的 Public 密钥以匹配私钥
- 您以编程方式将 Base64String 转换为 Json。这对于
JWT
调试器 是不可行的
使用下面的代码,我能够构建一个解码的 JSON Web 令牌 (decodedToken
)。当我将其粘贴到 https://jwt.io 上的调试器时,header 和有效负载正确显示在右侧。但是当我将编码的令牌 (encodedToken
) 粘贴到调试器中时,我收到此消息:
Looks like your JWT payload is not a valid JSON object. JWT payloads must be top level JSON objects as per https://www.rfc-editor.org/rfc/rfc7519#section-7.2
它还在底部用大红色字母表示“无效签名”。
此外,当使用编码令牌时,header区域显示我的解码header,有效负载区域显示我的整个解码令牌。所以 jwt.io 以某种方式成功解码了 JWT。但它不应该试图将整个解码令牌的 JSON 解析为一个单元。它应该尝试分别解析 header 的 JSON 和有效载荷部分。
我想知道为什么 jwt.io 不能完全满足我的编码令牌的有效负载。 decodedToken
和 encodedToken
的值在下面的源代码中显示为注释。谢谢。
private static string GetEncodedToken(string privateKey)
{
JObject header = JObject.FromObject(new { alg = "ES384", typ = "JWT" });
JObject payload = JObject.FromObject(new { name = "value" });//simple test JSON data
string decodedToken = Base64URLEncode(header) + "." + Base64URLEncode(payload);
//eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidmFsdWUifQ
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
using (ECDsa ecdsa = ECDsa.Create())
{
ecdsa.ImportECPrivateKey(privateKeyBytes, out _);
string encodedToken = JWT.Encode(decodedToken, ecdsa, JwsAlgorithm.ES384);
//eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ZXlKaGJHY2lPaUpGVXpNNE5DSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnVZVzFsSWpvaWRtRnNkV1VpZlE.kYj0M2GNC5w9oRrIVcHJ9dSQLbOEjNjxd61zSXD5iz0nBRRWMWyxj2l1DAhKPa_hpaFUscuubCzYe_W1SKpo3s06on-hYnICgQH4fVoAwZxiM_N4W761jecOExfivztn
return encodedToken;
}
}
private static string Base64URLEncode(JObject jObject)
{
string jsonString = jObject.ToString(Formatting.None);
byte[] jsonBytes = Encoding.UTF8.GetBytes(jsonString);
string escapedBase64 = Convert.ToBase64String(jsonBytes).TrimEnd('=').Replace('+', '-').Replace('/', '_');
return escapedBase64;
}
更新
感谢您到目前为止的回答。我想我已经接近了,但是 jwt.io 仍然说“签名无效”,即使我已经粘贴了 public 密钥。使用以下信息,我希望有人能告诉我为什么我的签名被认为是无效的。
为了在 whosebug.com 上调试这种情况,我生成了一个临时私钥:
MIGkAgEBBDBywQ7LVcyOGzxJ0Tpjpww2zUZbbtb3WVm4A3uv7ho31jJzQRYTpSqR7+ORAdoxmamgBwYFK4EEACKhZANiAASG50vW1r/O1XmUbTBb6yx1YSABh1USA6MJ8HJnYJ58tjGGVPL88a6Z1gOUlAsHtNhL44PhnTNTNNFdaH2Z41yn7oZmBhuon0vuUNFic2HDpfa/uFwRUAmhSBQz8hu+980=
我用我的私钥初始化了一个 ecdsa
的实例,并用 Convert.ToBase64String(ecdsa.ExportSubjectPublicKeyInfo())
生成了一个 public 密钥:
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEhudL1ta/ztV5lG0wW+ssdWEgAYdVEgOjCfByZ2CefLYxhlTy/PGumdYDlJQLB7TYS+OD4Z0zUzTRXWh9meNcp+6GZgYbqJ9L7lDRYnNhw6X2v7hcEVAJoUgUM/IbvvfN
这是更新后的代码:
private static string GetSignedEncodedToken(string privateKey)
{
JObject payload = JObject.FromObject(new { name = "value" });//simple test JSON data
string payloadString = payload.ToString(Formatting.None);
byte[] privateKeyBytes = Convert.FromBase64String(privateKey);
using (ECDsa ecdsa = ECDsa.Create())
{
ecdsa.ImportECPrivateKey(privateKeyBytes, out _);
string signedEncodedToken = JWT.Encode(payloadString, ecdsa, JwsAlgorithm.ES384);
return signedEncodedToken;
}
}
这是签名的编码令牌:eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ew0KICAibmFtZSI6ICJ2YWx1ZSINCn0.KpJAgc3-yaoGmHGAXHOeH3BPgpxdBRm461yWia60dgjuQHG5iLnwLQtQgdZtsHnI-bEK_wdmvu85ZrF7n-TdWiFb4FQxGeLBeeRfnMLJhKfInu_7MYEWPS2Ohm4yBAqg
更新解决方案
正如 jps 所提到的,我需要用“-----BEGIN PUBLIC KEY-----”和“-----END PUBLIC 键-----”。然后 jwt.io 显示“签名已验证”。
这里所说的decodedToken
基本上已经是没有签名的编码令牌了。函数 JWT.Encode
采用第一个参数并重复您已经手动执行的操作,即它为您创建一个 base64url 编码的 header 和有效负载,然后对令牌进行签名。您不需要创建自己的 header,也不需要关心 base64url 编码。
因此您只需要将您的 payload
(不是 base64 编码)传递到那里。结果是一个签名的令牌。
并且 jwt.io 显示“无效签名”,因为您可能没有将 public 密钥传递给右栏中的“public 密钥”字段。不知道 public 密钥,无法验证签名。
当您在此处粘贴 public 键时,确保它有 header 和页脚行 -----BEGIN PUBLIC KEY-----
-----END PUBLIC KEY-----
,然后验证应该可以正常工作。
您提供的令牌,我在 jwt.io
调试器中使用了相同的令牌并且可以看到几个问题:
eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.ZXlKaGJHY2lPaUpGVXpNNE5DSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnVZVzFsSWpvaWRtRnNkV1VpZlE.kYj0M2GNC5w9oRrIVcHJ9dSQLbOEjNjxd61zSXD5iz0nBRRWMWyxj2l1DAhKPa_hpaFUscuubCzYe_W1SKpo3s06on-hYnICgQH4fVoAwZxiM_N4W761jecOExfivztn
解码详情如下:
Header (which is correct):
{
"alg": "ES384",
"typ": "JWT"
}
Payload (which is not correct):
"eyJhbGciOiJFUzM4NCIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidmFsdWUifQ"
因为有效负载应该是 Json,而不是 Base64Encoded
字符串。您应该能够修改它以生成新的令牌。
Now Main Error:
解码调试器肯定需要Public密钥,它可以与私钥匹配,如果你使用非对称加密,如果你使用Symmetric encryption
那么两个密钥将是相同的。
您还可以选择添加私钥以生成具有修改算法或负载的新令牌。
Programmatically you are able to see the details:
- 您正在提供正确的 Public 密钥以匹配私钥
- 您以编程方式将 Base64String 转换为 Json。这对于
JWT
调试器 是不可行的