Spring应用生成的JWT无法在NodeJS中验证,求问题排查
JWT跨Java Spring与NodeJS验证失败问题排查
问题描述
我开发了一个基于Java Spring的认证微服务,负责生成JWT,对应的JWT工具类代码如下:
import io.jsonwebtoken.*; import io.jsonwebtoken.security.SignatureException; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; import java.util.Date; @Component public class JwtTokenProvider { @Value("${jwt.secret}") private String APP_SECRET; @Value("${jwt.expiresIn}") private long EXPIRES_IN; public String generateJwtToken(Authentication auth) { CustomUserDetails userDetails = (CustomUserDetails) auth.getPrincipal(); Date expireDate = new Date(new Date().getTime() + EXPIRES_IN); return Jwts.builder() .setSubject(Long.toString(userDetails.getId())) .setIssuedAt(new Date()) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS256, APP_SECRET) .compact(); } public boolean validateToken(String token) { try { Jwts.parser().setSigningKey(APP_SECRET).parseClaimsJws(token); return !isTokenExpired(token); } catch (SignatureException e) { return false; } } }
在application.properties中配置了256位密钥:
# JWT jwt.secret=92502665b0711fc987959b89d3958a26b2f8f60a8963263360192b89e7c0fa44 jwt.expiresIn=604800
该JWT在Spring应用内验证正常,但在NodeJS服务中使用jsonwebtoken库验证时,始终返回Invalid Signature错误,无法获取负载内容。NodeJS验证代码如下:
const jwt = require('jsonwebtoken'); const getAccessToRoute = (req, res, next) => { const { JWT_SECRET_KEY } = process.env; if (!isTokenIncluded(req)) { // return token not found } // extract the token from header const accessToken = getAccessTokenFromHeader(req); jwt.verify(accessToken, JWT_SECRET_KEY, async (err, decodedUserInfos) => { console.log("DECODED USER INFOS", decodedUserInfos); // undefined if (err) { console.log(err.message) return res.status(401).json({ message: "Invalid or expired token" }) } req.loggedUser = { id: decodedUserInfos.id, }; next(); }) };
.env文件中配置的JWT密钥:
# JWT JWT_SECRET_KEY=92502665b0711fc987959b89d3958a26b2f8f60a8963263360192b89e7c0fa44
两端密钥与签名算法完全一致,请问问题出在哪里?
问题原因与解决方案
核心原因:两端密钥处理逻辑不一致
Java的JJWT库在使用signWith(SignatureAlgorithm.HS256, APP_SECRET)时,会直接将字符串密钥作为原始UTF-8字符串用于HMAC签名;而NodeJS的jsonwebtoken库默认会把传入的字符串密钥当作Base64编码的密钥进行解码,再用于签名验证。这就导致两端实际使用的签名密钥不匹配,触发Invalid Signature错误。
两种解决方案
方案一:修改NodeJS代码适配Java的密钥处理逻辑
在jwt.verify方法中明确指定编码格式为utf8,告知库直接使用原始字符串密钥,无需Base64解码;同时注意Java端用setSubject设置的用户ID,在JWT负载中对应字段是sub而非id:
jwt.verify(accessToken, JWT_SECRET_KEY, { algorithms: ['HS256'], encoding: 'utf8' }, async (err, decodedUserInfos) => { console.log("DECODED USER INFOS", decodedUserInfos); if (err) { console.log(err.message) return res.status(401).json({ message: "Invalid or expired token" }) } req.loggedUser = { id: decodedUserInfos.sub, }; next(); })
方案二:修改Java代码适配NodeJS的默认处理逻辑
将Java端的字符串密钥转换为Base64编码后再用于签名,确保两端密钥处理逻辑一致:
import java.util.Base64; // ... 其他代码不变 return Jwts.builder() .setSubject(Long.toString(userDetails.getId())) .setIssuedAt(new Date()) .setExpiration(expireDate) .signWith(SignatureAlgorithm.HS256, Base64.getEncoder().encodeToString(APP_SECRET.getBytes())) .compact();
修改后NodeJS端保持现有代码即可,无需额外配置。
额外验证点
- 确认两端密钥完全一致,检查
.env和application.properties中的密钥是否存在空格、换行或大小写差异。 - 用JWT解析工具查看生成的token的header部分,确认
alg字段为HS256,确保签名算法一致。
内容的提问来源于stack exchange,提问作者anileates
相关产品推荐
相关产品推荐

