使用RS256算法的JWT验证抛出JsonWebTokenError: invalid signature问题排查
问题分析与修复方案
核心错误:密钥对不匹配
你在ServerA用自身私钥safety-private.key签名JWT,但ServerB却使用自己生成的serverB-public.key验证——这是完全错误的逻辑。RSA签名验证的规则是:私钥签名,对应公钥验证,ServerB必须使用ServerA的公钥safety-public.key来验证ServerA签名的JWT,而非生成独立的新密钥对。
次要问题与优化点
- 未校验JWT标准字段
ServerA生成JWT时指定了issuer(签发者)、audience(受众)、subject(主题),但ServerB的验证配置中未开启这些字段的校验。即使签名正确,后续也可能因字段不匹配导致验证失败,需补充校验配置:
const rsaVerifyOptions = { algorithms: ["RS256"], issuer: process.env.ISSUER, // 必须与ServerA的ISSUER环境变量值一致 audience: process.env.FORM_API_URL, // 必须与ServerA的FORM_API_URL环境变量值一致 // 若需校验subject,可根据场景动态传入或配置固定值 };
- 重复读取密钥文件
ServerA的getSigningConfig和ServerB的getVerifyConfig中重复调用密钥加载方法,会导致重复读取文件,可优化为单次读取:
- ServerA优化:
getSigningConfig(subject) { const rsaSignOptions = { algorithm: 'RS256', expiresIn: 15 * 60, issuer: process.env.ISSUER, audience: `${process.env.FORM_API_URL}`, }; const privateKey = this.exportRSAKey(); if (privateKey) { return { options: { ...rsaSignOptions, subject }, secret: privateKey, }; } }
- ServerB优化:
function getVerifyConfig(subject) { const publicKey = exportRSAKey(); if (publicKey) { return { options: { ...rsaVerifyOptions, subject }, // 需校验subject时添加 secret: publicKey, }; } }
getVerifyConfig调用参数缺失
ServerB的verifyToken中调用getVerifyConfig()时未传入subject参数,虽当前未使用该参数,但后续开启subject校验会导致验证失败,需补充参数:
function verifyToken(token, subject) { const { options, secret } = getVerifyConfig(subject); try { return jwt.verify(token, secret, options); } catch (err) { console.log(err); return null; } }
同时在decodeAndVerify中调用时传入对应subject值。
修复步骤
- 将ServerA的
safety-public.key复制到ServerB仓库中; - 修改ServerB的
JWT_RSA_PUBLIC_KEY环境变量,指向复制后的safety-public.key路径; - 按照上述优化点调整代码中的验证配置和密钥读取逻辑;
- 确保ServerA和ServerB的
ISSUER、FORM_API_URL等环境变量值完全一致。
内容的提问来源于stack exchange,提问作者Ashish Khokhariya
相关产品推荐
相关产品推荐

