JJWT 生成的令牌具有无效签名
JJWT generated token has an invalid signature
我正在使用 JJWT 库生成我的 JWT 令牌。我按如下方式生成我的令牌。我使用虚拟值作为我的密钥。
我们可以假设 jwt.security.key=security-key
@Value("${jwt.security.key}")
private String key;
@Value("${ws.issuer}")
private String issuer;
static final long ONE_MINUTE_IN_MILLIS=60000;
static final long TOKEN_DURATION_IN_MIN=30L;
private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
@Override
public String issueToken(String userName) {
long nowMillis = System.currentTimeMillis();
long expMillis = nowMillis + (ONE_MINUTE_IN_MILLIS * TOKEN_DURATION_IN_MIN);
return Jwts
.builder()
.setId("01")
.setIssuedAt(new Date(nowMillis))
.setHeaderParam("typ","JWT")
.setSubject(userName)
.setIssuer(issuer)
.setExpiration(new Date(expMillis))
.signWith(signatureAlgorithm, key).compact();
}
虽然令牌可以成功解码。每次我从 jwt.io 调试器验证它的签名时,它总是导致签名无效。可以看出here.
security-key
不是有效的 Base64 编码字符串。阅读 JavaDoc 和 signWith(SignatureAlgorithm, String)
方法的参数名称:
/**
* Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
*
* <p>This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
* byte array is used to invoke {@link #signWith(SignatureAlgorithm, byte[])}.</p>
*
* @param alg the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS.
* @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signing key to use to digitally sign the
* JWT.
* @return the builder for method chaining.
*/
JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey);
此外,为什么不考虑 jwt.io
可能被破坏?不是权威的jwt工具
最后,我要指出的是,您永远不应使用纯文本字符串或随机字符串作为签名密钥。数字签名总是用字节数组计算的。如果您希望密码学是安全的,您应该始终为您正在使用的签名算法使用足够长度的安全随机字节数组。
看一下JJWT的Keys.secretKeyFor
生成足够长和足够强的密钥的方法。
jwt.io
站点具有误导性,因为它没有使这一点变得明显,并暗示您可以使用任何旧字符串作为签名密钥。虽然技术上 可能,但您绝对不应该这样做。如果您需要将它们表示为字符串,则应始终使用安全随机字节数组,然后对它们进行 Base64 编码。这就是为什么接受字符串作为键的 JJWT 方法假定它是 Base64 编码的——因为如果不是,您可能使用了无效或格式不正确的键。
我正在使用 JJWT 库生成我的 JWT 令牌。我按如下方式生成我的令牌。我使用虚拟值作为我的密钥。
我们可以假设 jwt.security.key=security-key
@Value("${jwt.security.key}")
private String key;
@Value("${ws.issuer}")
private String issuer;
static final long ONE_MINUTE_IN_MILLIS=60000;
static final long TOKEN_DURATION_IN_MIN=30L;
private SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
@Override
public String issueToken(String userName) {
long nowMillis = System.currentTimeMillis();
long expMillis = nowMillis + (ONE_MINUTE_IN_MILLIS * TOKEN_DURATION_IN_MIN);
return Jwts
.builder()
.setId("01")
.setIssuedAt(new Date(nowMillis))
.setHeaderParam("typ","JWT")
.setSubject(userName)
.setIssuer(issuer)
.setExpiration(new Date(expMillis))
.signWith(signatureAlgorithm, key).compact();
}
虽然令牌可以成功解码。每次我从 jwt.io 调试器验证它的签名时,它总是导致签名无效。可以看出here.
security-key
不是有效的 Base64 编码字符串。阅读 JavaDoc 和 signWith(SignatureAlgorithm, String)
方法的参数名称:
/**
* Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
*
* <p>This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
* byte array is used to invoke {@link #signWith(SignatureAlgorithm, byte[])}.</p>
*
* @param alg the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS.
* @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signing key to use to digitally sign the
* JWT.
* @return the builder for method chaining.
*/
JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey);
此外,为什么不考虑 jwt.io
可能被破坏?不是权威的jwt工具
最后,我要指出的是,您永远不应使用纯文本字符串或随机字符串作为签名密钥。数字签名总是用字节数组计算的。如果您希望密码学是安全的,您应该始终为您正在使用的签名算法使用足够长度的安全随机字节数组。
看一下JJWT的Keys.secretKeyFor
生成足够长和足够强的密钥的方法。
jwt.io
站点具有误导性,因为它没有使这一点变得明显,并暗示您可以使用任何旧字符串作为签名密钥。虽然技术上 可能,但您绝对不应该这样做。如果您需要将它们表示为字符串,则应始终使用安全随机字节数组,然后对它们进行 Base64 编码。这就是为什么接受字符串作为键的 JJWT 方法假定它是 Base64 编码的——因为如果不是,您可能使用了无效或格式不正确的键。