问题描述
我正在使用 spring 安全性,并创建了一个 JWT 检查器。到目前为止,它只检查过期时间。
问题是我暴露了两个不同的api,调用者也使用不同的公钥/私钥来生成我控制的jwt(s),这意味着我有两个不同的公钥可以检查对应的jwt给他们。
仅保留一个检查令牌但也在公钥之间切换的函数的最佳方法是什么?
示例:
public class JwtControlValid {
@Value("${public.key.A}") // from application.properties
private String pubKeyA;
@Value("${public.key.B}")
private String pubKeyB;
private RSAPublicKey getPubKey() {
try {
KeyFactory kf = KeyFactory.getInstance("RSA");
// if(caller A)
X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKeyA));
// if (caller B)
X509EncodedKeySpec keySpecX509 = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKeyB));
RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(keySpecX509);
return pubKey;
}catch ...
和另一个使用第一个判断真假的函数:
public boolean isJwtValid(String jwt) {
try {
Jwts.parser().setSigningKey(getPublicKey()).parseClaimsJws(jwt);
return true;
} catch ....
return false;
两个公钥都是 RSA public keys
是否有一种干净的方法可以根据我收到的 jwt 在公钥之间切换?
解决方法
问题是我暴露了两个不同的api,调用者也使用不同的公钥/私钥来生成我控制的jwt(s),这意味着我有两个不同的公钥可以检查对应的jwt给他们。
是的,这是一个问题,不是标准。为每个客户端设置公钥的效果不佳,通常不受支持。
开箱即用的 Spring 支持 trusting single asymmetric key 但不支持多个,因为这不是标准,我不推荐这种方法。
如果您想支持多个密钥,则应改用 JWKs
,这是发行服务公开的多个密钥。
这基本上意味着发行您的令牌的颁发者(服务器/服务)有一个端点,所有资源服务器都可以通过该端点获取验证令牌所需的公钥。
优点是可以轮换密钥,可以检查多个 JWK,具有可扩展性和安全性等。
如果您仍然想走我强烈不推荐的路径,那么您可以例如使用其接口实现两个 JwtAuthenticationProvider
。
您可以通过实现 AuthenticationManagerResolver
来决定使用哪个。
我强烈建议您阅读整个 JWT flow in the spring security official docs 并使用包含在 Spring Security 中的 Nimbus
而不是 JJwt
,后者只是一个额外的不需要的依赖项。
我只想包括,编写自定义安全性从来都不是一件好事,它所需要的只是自定义安全性代码中的一个错误,而您的整个安全性可能毫无用处。这就是为什么有标准、RFC 和既定流程的原因。避免自定义安全解决方案。