Retrieve Keycloak user data using received access

2019-04-17 02:35发布

问题:

I am developing a WildFly-Backend (in Java) that accepts HTTP requests (from a custom Frontend) that are signed with the user's Keycloak bearer access token through the "Authorization" HTTP header.

The Backend connection itself is already secured with the Keycloak adapter for WildFly, but internally, I want to check who the user is (user groups, name, etc.) and return verying responses.

I figured that it would be possible to just send this data from the Frontend, but then people could easily fake the request once they have an access token. Is there a way to retrieve things like user data while only having the access token?

回答1:

I have since figured out how to solve the issue!

First, you add near the top of the class the following:

@Context
SecurityContext securityContext;

This will be injected with the context of the server's security. The make this work with Keycloak, the WildFly will need to have the Wildfly adapter installed and the web.xml must be configured to use Keycloak.

Before we proceed, we need the Keycloak-Core library, e.g. per Maven:

<!-- https://mvnrepository.com/artifact/org.keycloak/keycloak-core -->
<dependency>
    <groupId>org.keycloak</groupId>
    <artifactId>keycloak-core</artifactId>
    <version>4.4.0.Final</version>
</dependency>

4.4.0.Final was the latest version as of writing this answer; it is advised to use either the latest version or the version that matches that of the Keycloak server.

Next, at the point where you want to retrieve user info, you retrieve the UserPrincipal:

if (securityContext != null && securityContext.getUserPrincipal() instanceof KeycloakPrincipal) {
    KeycloakPrincipal principal = ((KeycloakPrincipal) securityContext.getUserPrincipal());

The additional checks are failsaves, so that non-Keycloak configurations can be handeled separately.

From the casted KeycloakPrinciple, retrieve the KeycloakSecurityContext and from there the Token of the user:

AccessToken token = principal.getKeycloakSecurityContext().getToken();

In some cases (depending on the version of your Keycloak and/or WildFly), getToken() might return null. In these cases, use getIdToken():

IDToken token = principal.getKeycloakSecurityContext().getIdToken();

AccessToken extends IDToken, so you have full functionality (for this context) in both cases.

From the token, all user data can be extracted. As an example, we get the user's username. In Keycloak, this propery is called "preferred username".

String user = token.getPreferredUsername();

And you're done! Your full code could now look like this:

if (securityContext != null && securityContext.getUserPrincipal() instanceof KeycloakPrincipal) {
    KeycloakPrincipal principal = ((KeycloakPrincipal) securityContext.getUserPrincipal());
    AccessToken token = principal.getKeycloakSecurityContext().getToken();
    // IDToken token = principal.getKeycloakSecurityContext().getIdToken();

    System.out.println("User logged in: " + token.getPreferredUsername());
} else {
    System.out.println("SecurityContext could not provide a Keycloak context.");
}