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

Java与Python生成JWT签名不一致问题及Python代码修正需求

问题:Java与Python生成的JWT签名不一致

我分别用Java和Python实现了JWT生成逻辑,但两者输出的签名部分完全不同。尝试过ChatGPT但未解决问题,怀疑差异出在JSON序列化或字符串处理层面,需要解释原因并修改Python代码,让最终生成的JWT完全一致。

现有代码及结果

Python代码(使用PyJWT库)

payload = {"login_user_key": "b7c5443c-5395-46b0-b6c1-d940fd686880"}
secret = 'abcdefghijklmnopqrstuvwxyz'
headers = {"alg": "HS512", "typ": "JWT"}
encoded_jwt = jwt.encode(payload, secret, algorithm='HS512', headers=headers)
print(encoded_jwt)

输出结果:
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJsb2dpbl91c2VyX2tleSI6ImI3YzU0NDNjLTUzOTUtNDZiMC1iNmMxLWQ5NDBmZDY4Njg4MCJ9.fmhdCmM4BJBOASK_UXtRoszP0Q614mDlQ3iDU9_ZFCr--jh--OHG8o5aCG4Zgpcpmsry9NH1LY-4Bd_NN0mmQQ

Java代码(使用JJWT库)

String secret = "abcdefghijklmnopqrstuvwxyz";
Map<String, Object> claims = new HashMap<>();
claims.put("login_user_key", "b7c5443c-5395-46b0-b6c1-d940fd686880");
String jwttoken = Jwts.builder()
        .setHeaderParam("alg", "HS512")
        .setHeaderParam("typ", "JWT")
        .setClaims(claims)
        .signWith(SignatureAlgorithm.HS512, secret).compact();
System.out.println(jwttoken);

输出结果:
eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJsb2dpbl91c2VyX2tleSI6ImI3YzU0NDNjLTUzOTUtNDZiMC1iNmMxLWQ5NDBmZDY4Njg4MCJ9.Gat6BTTXtwC_XWN4pZjqC-x4Bw24xfpNXmLIMSysa3FJaPvpnXcjO0wp6FBlKtrfYyqZRQARQbE4rGwhAOY_eg

差异原因

  1. 库版本或实现细节差异:旧版本的PyJWT在JSON序列化(如是否自动添加空格)、Base64URL编码规则或HMAC签名的字节处理逻辑上,与JJWT库存在隐性差异,导致最终签名不一致。
  2. 密钥处理的细微差别:虽然密钥字符串相同,但不同库对字符串转字节数组的编码方式(如是否强制使用UTF-8)或HMAC算法的底层实现可能存在差异。

修改后的Python代码

方案1:手动实现JWT生成流程(完全可控)

通过手动完成每一步操作,确保与Java的JJWT逻辑完全对齐:

import hmac
import hashlib
import base64
import json

def base64url_encode(data):
    # 实现JWT标准的URL安全Base64编码:去掉末尾=,替换+为-、/为_
    return base64.urlsafe_b64encode(data).rstrip(b'=').decode('utf-8')

def generate_jwt(payload, secret, headers):
    # 序列化header为无空格的紧凑JSON
    header_json = json.dumps(headers, separators=(',', ':')).encode('utf-8')
    header_b64 = base64url_encode(header_json)
    
    # 序列化payload为无空格的紧凑JSON
    payload_json = json.dumps(payload, separators=(',', ':')).encode('utf-8')
    payload_b64 = base64url_encode(payload_json)
    
    # 拼接header和payload,生成签名输入
    signature_input = f"{header_b64}.{payload_b64}".encode('utf-8')
    
    # 计算HMAC-SHA512签名
    signature = hmac.new(secret.encode('utf-8'), signature_input, hashlib.sha512).digest()
    signature_b64 = base64url_encode(signature)
    
    # 拼接最终JWT
    return f"{header_b64}.{payload_b64}.{signature_b64}"

# 测试代码
payload = {"login_user_key": "b7c5443c-5395-46b0-b6c1-d940fd686880"}
secret = 'abcdefghijklmnopqrstuvwxyz'
headers = {"alg": "HS512", "typ": "JWT"}

encoded_jwt = generate_jwt(payload, secret, headers)
print(encoded_jwt)

方案2:使用新版PyJWT并指定序列化规则

确保安装PyJWT 2.8.0及以上版本,通过指定标准JSON编码器避免序列化差异:

import jwt
import json

payload = {"login_user_key": "b7c5443c-5395-46b0-b6c1-d940fd686880"}
secret = 'abcdefghijklmnopqrstuvwxyz'
headers = {"alg": "HS512", "typ": "JWT"}

# 指定标准JSON编码器,确保生成紧凑无空格的JSON字符串
encoded_jwt = jwt.encode(
    payload,
    secret,
    algorithm='HS512',
    headers=headers,
    json_encoder=json.JSONEncoder
)
print(encoded_jwt)

两种方案生成的JWT都会与Java代码的输出完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 20:29:57