如何使用Java验证由Keycloak签名的JWT。

huangapple go评论95阅读模式
英文:

How to verify JWT signed by keycloak using java

问题

我有一个由Keycloak生成的JWT,采用RS256算法,类似于以下内容:

示例:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.YSFl77w-H2BIt9O-NPZ2f3G-Bf-DfKk9fMn2a4Kz64z0bTzzeA3tFAixXsqYeNBYWXWYJ83GQ2-SR1GfXnuTItBBGtb6NnwNchInZkUOVf7Ng7RvIv7GtBooByOv1aXzgKyH4P-M04lKKuZ_LwDm9Cjp9ENb7ylVKbPvRr-6DLlRvjQ

我需要解码并验证这个令牌,使用Keycloak的证书。

我可以通过API访问Keycloak的证书:

https://xxx.xxx.com.tr/auth/realms/myrealm/protocol/openid-connect/certs

在响应中,我有x5c字段:

{
    "keys": [
        {
            "kid": "j6DsCpPOz1RXJhtPR28sZ7LZLAEus",
            "kty": "RSA",
            "alg": "RS256",
            "use": "sig",
            "n": "m0oTFvyLhLGIciXfndxc7uhIKE2-q9nJQKByd0FVYe8Cd4CHDpTzzcYdPWRR-1_VKQ75wqpybRt-LnnTKPNCXrPtPDRn2GFihtYyyO8VjeVtnz-iYJJAHkdp25HlMtX9l-VjnQX9s70-lbMmCVCRTerw",
            "e": "AQAB",
            "x5c": [
                "MIICnTCCAYUCBgFzh2ZkQzANBgkqhkiG9w0BAQ50F/bO9PpWzJglQkU3q8CAwEAATANBgkqhkiG9w01faO/9ZzyiLMLsorUKzYPNAxc7Q9rLE0J2MCWfapx3/E4yyNjISuB1HpS5iF44OEhGHJlw7JQeogcZat0enB8yyXtP/cgBhCnrWwfugX8rHsWfHakBGdsoazR9w=="
            ],
            "x5t": "YF6LE97opzsTtD-yLNx9-Lo",
            "x5t#S256": "SdNCfMbCjvcq-JY3iiGAj7De9Hal_0Cck-bDFK3Ow"
        }
    ]
}

我可以在https://jwt.io/上验证这个JWT,如果我将x5c部分放在----CERTIFICATE-----标签中。

-----BEGIN CERTIFICATE-----
MIICnTCCAYUCBgFzh2ZkQzANBgkqhkiG9w0BAQ50F/bO9PpWzJglQkU3q8CAwEAATANBgkqhkiG9w01faO/9ZzyiLMLsorUKzYPNAxc7Q9rLE0J2MCWfapx3/E4yyNjISuB1HpS5iF44OEhGHJlw7JQeogcZat0enB8yyXtP/cgBhCnrWwfugX8rHsWfHakBGdsoazR9w==
-----END CERTIFICATE-----

如何在Java中验证相同的内容?

我尝试了一些方法,但失败了。

英文:

I have JWT generated by keyCloack, RS256 something like this

sample:

eyJhbGciOwia2lkIiA6ICJtSG1lajZEc09GaV9MejdSMjhzWjdMWkxBRXVzIn0.eyBzA2MzQvOTcwNjM1L1NNUyIsIi83Ni83NS9TTVMiXSwicHJYW1lIjoidGVzdDEwNUB1c2VyLmNvbSIsInVzZXJOYW1lIjoidGVzdDEwNUB1c2VyLmNvbSIsInVzZXJJZCI6IjU4NDM2NmQ4LWU5NDItNGJhNy04OGVlLWMyZTBlODhmZmY5ZCIsImVtYWlsIjoidGVzdDEwNUB1c2VyLmNvbSJ9.4TgC1MLyUl1P36oD6FafBCh0peEaCBmkyLheVjnlBu8uePl9xgEN6wdeWe

I need to decode and validate this token using keycloack certificate.

i can reach the keycloack certificate over api.

https://xxx.xxx.com.tr/auth/realms/myrealm/protocol/openid-connect/certs

in the response, I have x5c field.

{
    "keys": [
        {
            "kid": "j6DsCpPOz1RXJhtPR28sZ7LZLAEus",
            "kty": "RSA",
            "alg": "RS256",
            "use": "sig",
            "n": "m0oTFvyLhLGIciXfndxc7uhIKE2-q9nJQKByd0FVYe8Cd4CHDpTzzcYdPWRR-1_VKQ75wqpybRt-LnnTKPNCXrPtPDRn2GFihtYyyO8VjeVtnz-iYJJAHkdp25HlMtX9l-VjnQX9s70-lbMmCVCRTerw",
            "e": "AQAB",
            "x5c": [
                "MIICnTCCAYUCBgFzh2ZkQzANBgkqhkiG9w0BAQ50F/bO9PpWzJglQkU3q8CAwEAATANBgkqhkiG9w01faO/9ZzyiLMLsorUKzYPNAxc7Q9rLE0J2MCWfapx3/E4yyNjISuB1HpS5iF44OEhGHJlw7JQeogcZat0enB8yyXtP/cgBhCnrWwfugX8rHsWfHakBGdsoazR9w=="
            ],
            "x5t": "YF6LE97opzsTtD-yLNx9-Lo",
            "x5t#S256": "SdNCfMbCjvcq-JY3iiGAj7De9Hal_0Cck-bDFK3Ow"
        }
    ]
}

I can validate this jwt over https://jwt.io/ if I put the x5c part within ----CERTIFICATE----- tag

-----BEGIN CERTIFICATE-----
MIICnTCCAYUCBgFzh2ZkQzANBgkqhkiG9w0BAQ50F/bO9PpWzJglQkU3q8CAwEAATANBgkqhkiG9w01faO/9ZzyiLMLsorUKzYPNAxc7Q9rLE0J2MCWfapx3/E4yyNjISuB1HpS5iF44OEhGHJlw7JQeogcZat0enB8yyXtP/cgBhCnrWwfugX8rHsWfHakBGdsoazR9w==
-----END CERTIFICATE----- 

how can I verify same thing in Java?

I tried couple of things but it failed.

答案1

得分: 3

我找到了方法。

首先,我们需要登录到 Keycloak 控制台,您可以找到与 realm 相关的公钥。

现在您已经从 Keycloak 获取了公钥和用户的 JWT。

您需要首先导入相关的库。

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.11.2</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.11.2</version>
    <scope>runtime</scope>
</dependency>

之后,这是逻辑部分。

String token = "ghfghfdhdhdfhdfghdhdfhdfhdfhhdf";
String rsaPublicKey = "awdasdsadaefafafaef5df65d4f";
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(rsaPublicKey));
KeyFactory kf = KeyFactory.getInstance("RSA");
PublicKey publicKey = kf.generatePublic(keySpec);

我们已经有了公钥,现在需要验证它。

Jws<Claims> jwt = null;
try {
    jwt = Jwts.parserBuilder()
            .setSigningKey(publicKey)
            .build()
            .parseClaimsJws(token);
} catch (Exception e) {
    // 如果出现错误,这意味着令牌无效。
}
英文:

I found the way.

First, we need to login keycloack console, you can reach the public key related with realm.

now you have publickey from keycloak and JWT from user.

you need to import related libraries first.

&lt;dependency&gt;
			&lt;groupId&gt;io.jsonwebtoken&lt;/groupId&gt;
			&lt;artifactId&gt;jjwt-api&lt;/artifactId&gt;
			&lt;version&gt;0.11.2&lt;/version&gt;
		&lt;/dependency&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;io.jsonwebtoken&lt;/groupId&gt;
			&lt;artifactId&gt;jjwt-impl&lt;/artifactId&gt;
			&lt;version&gt;0.11.2&lt;/version&gt;
			&lt;scope&gt;runtime&lt;/scope&gt;
		&lt;/dependency&gt;
		&lt;dependency&gt;
			&lt;groupId&gt;io.jsonwebtoken&lt;/groupId&gt;
			&lt;artifactId&gt;jjwt-jackson&lt;/artifactId&gt;
			&lt;version&gt;0.11.2&lt;/version&gt;
			&lt;scope&gt;runtime&lt;/scope&gt;
		&lt;/dependency&gt;

after that here is the logic.

String token = &quot;ghfghfdhdhdfhdfghdhdfhdfhdfhhdf&quot;;
String rsaPublicKey = &quot;awdasdsadaefafafaef5df65d4f&quot;;
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(rsaPublicKey));
KeyFactory kf = KeyFactory.getInstance(&quot;RSA&quot;);
PublicKey = kf.generatePublic(keySpec);

we have publickey, we need to verify it

Jws&lt;Claims&gt; jwt = null;
try {
    jwt = Jwts.parserBuilder()
    		            .setSigningKey(publicKey)
    		            .build()
    		            .parseClaimsJws(token);
    		} catch (Exception e) {
    			// if you get error, that means token is invalid.
    		}

答案2

得分: 1

我认为你可以使用jose4j库来实现这个功能。

HttpsJwks httpsJkws = new HttpsJwks("https://xxx.xxx.com.tr/auth/realms/myrealm/protocol/openid-connect/certs");
HttpsJwksVerificationKeyResolver httpsJwksKeyResolver = new HttpsJwksVerificationKeyResolver(httpsJkws);

// 使用JwtConsumerBuilder构建适当的JwtConsumer,它将用于验证和处理JWT。
// 但在这种情况下,将其提供给HttpsJwksVerificationKeyResolver实例,而不是明确设置验证密钥。

jwtConsumer = new JwtConsumerBuilder()
    // ... JwtConsumerBuilder的其他设置 ...
    .setVerificationKeyResolver(httpsJwksKeyResolver)
    // ...
    .build();
英文:

I think you can use jose4j library for that.

HttpsJwks httpsJkws = new HttpsJwks(&quot;https://xxx.xxx.com.tr/auth/realms/myrealm/protocol/openid-connect/certs&quot;);
HttpsJwksVerificationKeyResolver httpsJwksKeyResolver = new HttpsJwksVerificationKeyResolver(httpsJkws);


// Use JwtConsumerBuilder to construct an appropriate JwtConsumer, which will
// be used to validate and process the JWT. But, in this case, provide it with
// the HttpsJwksVerificationKeyResolver instance rather than setting the
// verification key explicitly.

jwtConsumer = new JwtConsumerBuilder()
    // ... other set up of the JwtConsumerBuilder ...
    .setVerificationKeyResolver(httpsJwksKeyResolver)
    // ...
    .build();

huangapple
  • 本文由 发表于 2020年8月6日 17:38:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/63280826.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定