根据文档here和there,我设法建立了一个授权服务器,该服务器给出了使用非对称密钥签名的JWT访问令牌,资源服务器使用公钥的本地副本在本地验证。到现在为止还挺好。
我的最终目标是资源服务器在授权服务器上使用JWKS端点,并使用JWT中的'kid'标头在JWKS中查找正确的密钥并在本地验证,支持密钥轮换。我找到了how to make the Authorization Server expose a JWKS endpoint,还有how to specify the key-set-uri for the resource server。
但是,似乎没有办法
有没有办法做到这一点?
我找到了一种在jwks端点设置孩子的方法:
@FrameworkEndpoint
public class JwkSetEndpoint {
private final KeyPair keyPair;
public JwkSetEndpoint(KeyPair keyPair) {
this.keyPair = keyPair;
}
@GetMapping("/.well-known/jwks.json")
@ResponseBody
public Map<String, Object> getKey() {
RSAPublicKey publicKey = (RSAPublicKey) this.keyPair.getPublic();
RSAKey key = new RSAKey.Builder(publicKey)
.keyID("YOUR_KID_HERE")
.keyUse(KeyUse.SIGNATURE).build();
return new JWKSet(key).toJSONObject();
}
}
我没有找到的方法是在JWT的标题中设置它。
虽然有同样的问题我偶然发现了这篇文章。所以我希望它对某人有用。我不认为这是最好的解决方案,所以也许有人想出一个更好的答案,我希望像设置一些外部bean一样。
背景:Jwk存储正在将令牌头中的KID与内存中的KID进行比较,如果不可用,它将请求众所周知的端点
因此,将KID放在JwkSetEndpoint中将导致json文件与里面的孩子。在此旁边,您需要获取jwt标记的标头上的KID。
我的类中的解决方案扩展了JwtAccessTokenConverter
@Override
protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
String content = null;
try {
content = objectMapper.formatMap(getAccessTokenConverter().convertAccessToken(accessToken, authentication));
} catch (Exception e) {
throw new IllegalStateException("Cannot convert access token to JSON", e);
}
Map<String, String> headers = getJwtHeader();
String token = JwtHelper.encode(content, signer, headers).getEncoded();
return token;
}
在KID标头旁边,Tokenstore期望使用标头设置为签名。我还必须覆盖签名者对象,因为我遇到了一个hmac签名者而不是所需的RsaSigner。