You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python解密ASP.NET生成的JWT令牌遇签名验证错误,求解决

解密ASP.NET生成的加密JWT令牌问题

问题背景

需要解密ASP.NET应用生成的JWT令牌,ASP.NET端令牌生成代码如下:

public string GenerateJwtToken(ICollection<Claim> claims)
{
    var signingKey =
        new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Identity:Jwt:SigningKey"]));
    var encryptionKey =
        new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Identity:Jwt:EncryptionKey"]));

    var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha512);
    var expires = _systemClock.UtcNow.DateTime.AddHours(24);
    var issueDateTime = _systemClock.UtcNow.DateTime;

    var encryptingCredentials = new EncryptingCredentials(
        encryptionKey,
        JwtConstants.DirectKeyUseAlg,
        SecurityAlgorithms.Aes256CbcHmacSha512);

    var securityToken = new JwtSecurityTokenHandler().CreateJwtSecurityToken(
        _configuration["Identity:Jwt:Issuer"],
        _configuration["Identity:Jwt:Audience"],
        new ClaimsIdentity(claims),
        issueDateTime,
        expires,
        issueDateTime,
        signingCredentials,
        encryptingCredentials);

    return new JwtSecurityTokenHandler().WriteToken(securityToken);
}

尝试使用jwcrypto库解密时,遇到错误:

jwcrypto.jws.InvalidJWSSignature: Verification failed for all signatures["Failed: [InvalidJWSSignature('Verification failed')]"]

当前Python尝试代码:

from jwcrypto import jwt, jwk, jwe
import base64

s = "<Identity:Jwt:EncryptionKey>" # The same key that is used in the ASP.net app
base64_bytes = base64.b64encode(s.encode("utf-8"))
base64_string = base64_bytes.decode("utf-8")

# Convert the Base64 string to Base64Url
base64_string = base64_string.rstrip("=")
base64_string = base64_string.replace("+", "-")
base64_string = base64_string.replace("/", "_")

print(base64_string)

k = {"k": base64_string, "kty": "oct"}
key = jwk.JWK(**k)
token = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidHlwIjoiSldUIn0..4C1FW4w2BZ6Nq5jzM1jbdQ.LJqaiSsaIxRgFw9vTs8zNhHH824JJyfU6Jmxi7hta8OyeUO11Df4HuFzC-3PyVrhI0lICtGqmY6BeaaQkquJIz65XgOi9sdR1tBNHkc5bKjTyoXxW65QbdaDhvjpFJXoe66eTPn32tf2M6VDU6w1hJitQgVpq8v11rUf2YqP0g-vkZbxTmD-Cd5BY6hHSuJ_CJ1SDIYzVGKw7mDudM0Opm9EeXEbtVZCL7YagziG_WSryfCaUh9OLulre4SOvZ8T5t5duADEn4MHiYRUZjNbXZIhsWsLfxhINhspekoS4ha8rYQSIHH8208TD4wckQ3zx70XYNHbQiqSr3Atlt-zXPIG1MsfXZJOrg4-KFeKaWxlMfyx3iPiSRisILQm-ATGDnRxHewEuU0gwLyHkwTsyObO7zIuDs82RMgCB5jFs-PK27YHPplv26w9WDQ1F88Lbiumxv9j1zvF6rTQEFte7OnHJD9BpxTDmC9vvUNbdsBLn2tlhAtWKU-oBUOtA-vJIiWz3lt_Mz5Xj1G9WlcHtcUNi-kv_ZFDz45gmG-nhvHDZE3Sp8qnyko8W6tmDusXI6nTwseQ3FrQgUCR69jJ_bEvGjGzqrJ2Pv0qFcyNuHZglB8CvX3kALoMeRyYuV_ULD0wEDd8QET-w_6gKj1-aPfGqcWbJO0JRxphWNJcVLcicoe3fWqyXrmv6iPWZsKcmEYE2T3qco3dVeoYgC-EkPBROfHXzvBdb9ABqfW2dc782fPHXhahZkJJNfXaxNC6Lc8COe-DjQVUtU-z-VL6erhmgzb-G178A074q3kX2b1nDp4zEMs4t704SEdSyo4uKzamKwXtbc_XwKb-Xcda_udoWhW1KiQkJktHhYnZ6g1dcUjQ0G5R9P8hX3T597mNJyHq8lVr6hYhWXRZZLm_1w.VL2-nxFdi3b3-lUy-Oi0sQOPTwgVmdIkLV9TLBYNYUs"
ET = jwt.JWT(key=key, jwt=token, expected_type="JWE")
print(ET.claims)
ST = jwt.JWT(key=key, jwt=ET.claims)
print(ST.claims) 

问题原因

  1. 密钥混用:ASP.NET生成的是嵌套JWT(JWE包裹JWS),解密JWE需要用EncryptionKey,验证内部JWS需要用SigningKey,当前代码用加密密钥去验证签名,导致验证失败。
  2. 密钥编码错误:手动转换Base64到Base64Url容易出错,jwcrypto提供了更可靠的密钥构建方法。

正确解密代码

from jwcrypto import jwt, jwk

# 替换为ASP.NET配置中的实际密钥
ENCRYPTION_KEY = "<Identity:Jwt:EncryptionKey>"
SIGNING_KEY = "<Identity:Jwt:SigningKey>"

# 1. 构建加密密钥,解密JWE
encryption_jwk = jwk.JWK.from_bytes(ENCRYPTION_KEY.encode('utf-8'), kty='oct')
token = "eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2Q0JDLUhTNTEyIiwidHlwIjoiSldUIn0..4C1FW4w2BZ6Nq5jzM1jbdQ.LJqaiSsaIxRgFw9vTs8zNhHH824JJyfU6Jmxi7hta8OyeUO11Df4HuFzC-3PyVrhI0lICtGqmY6BeaaQkquJIz65XgOi9sdR1tBNHkc5bKjTyoXxW65QbdaDhvjpFJXoe66eTPn32tf2M6VDU6w1hJitQgVpq8v11rUf2YqP0g-vkZbxTmD-Cd5BY6hHSuJ_CJ1SDIYzVGKw7mDudM0Opm9EeXEbtVZCL7YagziG_WSryfCaUh9OLulre4SOvZ8T5t5duADEn4MHiYRUZjNbXZIhsWsLfxhINhspekoS4ha8rYQSIHH8208TD4wckQ3zx70XYNHbQiqSr3Atlt-zXPIG1MsfXZJOrg4-KFeKaWxlMfyx3iPiSRisILQm-ATGDnRxHewEuU0gwLyHkwTsyObO7zIuDs82RMgCB5jFs-PK27YHPplv26w9WDQ1F88Lbiumxv9j1zvF6rTQEFte7OnHJD9BpxTDmC9vvUNbdsBLn2tlhAtWKU-oBUOtA-vJIiWz3lt_Mz5Xj1G9WlcHtcUNi-kv_ZFDz45gmG-nhvHDZE3Sp8qnyko8W6tmDusXI6nTwseQ3FrQgUCR69jJ_bEvGjGzqrJ2Pv0qFcyNuHZglB8CvX3kALoMeRyYuV_ULD0wEDd8QET-w_6gKj1-aPfGqcWbJO0JRxphWNJcVLcicoe3fWqyXrmv6iPWZsKcmEYE2T3qco3dVeoYgC-EkPBROfHXzvBdb9ABqfW2dc782fPHXhahZkJJNfXaxNC6Lc8COe-DjQVUtU-z-VL6erhmgzb-G178A074q3kX2b1nDp4zEMs4t704SEdSyo4uKzamKwXtbc_XwKb-Xcda_udoWhW1KiQkJktHhYnZ6g1dcUjQ0G5R9P8hX3T597mNJyHq8lVr6hYhWXRZZLm_1w.VL2-nxFdi3b3-lUy-Oi0sQOPTwgVmdIkLV9TLBYNYUs"

# 解密JWE得到内部JWS令牌
jwe_token = jwt.JWT(key=encryption_jwk, jwt=token, expected_type="JWE")
jws_token_str = jwe_token.claims

# 2. 构建签名密钥,验证JWS并解析声明
signing_jwk = jwk.JWK.from_bytes(SIGNING_KEY.encode('utf-8'), kty='oct')
jws_token = jwt.JWT(key=signing_jwk, jwt=jws_token_str, expected_type="JWS")

print("解密并验证后的声明:")
print(jws_token.claims)

关键注意事项

  • 严格区分EncryptionKey和SigningKey,两者功能不同不可混用。
  • 使用jwk.JWK.from_bytes自动处理密钥编码,避免手动转换出错。
  • 解密时指定expected_type="JWE",验证时指定expected_type="JWS",确保库正确识别令牌类型。

内容的提问来源于stack exchange,提问作者Mohamad Fadil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 07:35:11