我正在编写后端微服务,该服务从前端接收具有Authorisation: Bearer ...
标头的请求,并从keycloak(位于docker容器内)获取令牌。
我从领域设置的“密钥”部分获得了RSA公共密钥来验证该令牌的签名,但是似乎当带有keycloak的容器重新启动时,它会重新生成一对密钥,并且在服务配置中设置的公共密钥变得无效。
从keycloak使用RSA公钥的正确方法是什么?是否可以通过某种方式将其配置为使用固定的密钥对进行领域设置?领域导出时是否导出密钥?或者,我必须使用http://keycloak:8080/auth/realms/:realm_name:
之类的网址从keycloak获取公钥,我宁愿不这样做,因为这会在keycloak和后端之间增加一个依赖关系。
答案 0 :(得分:0)
您应基于发行者身份服务器的/.well-known/jwks
端点来验证JWT令牌的签名。
1)查询发行者身份服务器的/.well-known/jwks
端点(JWKS代表JSON Web密钥集)
2)从JWKS中获得与我们正在验证的kid
令牌相同的Bearer
(密钥ID)的JWK(JSON Web密钥)。要从您的JWT令牌中获取kid
,请先使用jwt.io的调试器工具对其进行解码。
3)只要使用非对称密码算法(例如:RS256)验证身份服务器颁发的令牌,我们就只能使用公钥来验证签名(因此您不需要私钥)
4)可以从JWK检索公共密钥(它是JWK JSON中的x5c
条目)
5)使用此公钥验证JWT Bearer
令牌的签名。
例如,在Java中,您可以像这样进行验证:
// verify JWT signature based on Access Identity's JWKS RSA public key (RS256)
try {
Jwk jwk = new UrlJwkProvider(new URL(issuer + Constants.JWKS_ENDPOINT)).get(decodedJWT.getKeyId());
final PublicKey publicKey = jwk.getPublicKey();
if (!(publicKey instanceof RSAPublicKey)) {
throw new IllegalArgumentException("Key with ID " + decodedJWT.getKeyId() + " was found in JWKS but is not a RSA-key.");
}
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer(issuer)
.build(); //Reusable verifier instance
verifier.verify(bearerToken);
LOGGER.info("Token verified!");
} catch (Exception e) {
LOGGER.error(e.getMessage());
throw new InvalidAccessTokenException("JWTVerificationException - Invalid token signature.");
}