Java客户端刷新Keycloak令牌

10

想象一下,

以下是 Keyclock 中的 2 个客户端(2 个微服务)。

  • rest-service-1
  • rest-service-2

以下是 rest-service-2 中的角色

  • service-2-user

进行服务之间的调用,即:rest-service-1 调用 rest-service-2

'rest-service-1' 在 Keycloak 中配置有以下值

Access Type: confidential
Service Account Enabled: Yes

此外,在'rest-service-1'的“服务帐户角色”下,已添加/映射以下角色

Role for client rest-service-2: service-2-user

在为Keycloak调用客户端设置了2个客户端和服务帐户后,我创建了一个Spring Boot 2.0.3项目,并使用以下代码获取令牌。

@Bean
public AuthzClient authzClient(KeycloakSpringBootProperties kcProperties) {
  //org.keycloak.authorization.client.Configuration
  Configuration configuration =
      new Configuration(kcProperties.getAuthServerUrl(), 
                        kcProperties.getRealm(), 
                        kcProperties.getResource(),
                        kcProperties.getCredentials(), null);

  return AuthzClient.create(configuration);
}

这是我获取访问令牌的方法

@Autowired
private AuthzClient authzClient;

public AccessTokenResponse token() {
  return authzClient.obtainAccessToken();
}

以下是接收到的令牌:

{
  "access_token": ${access-token},
  "expires_in": 300,
  "refresh_expires_in": 1800,
  "refresh_token": ${refresh-token},
  "token_type": "bearer",
  "id_token": null,
  "not-before-policy": 0,
  "session_state": "6f284b2f-5bb6-4018-8acd-b83923ebb7d7",
  "scope": "profile email"
}

注意:我更换了令牌以使其简短。

问题:

如何使用上面提到的刷新令牌并获取新的访问令牌?AuthzClient是否支持此功能?如果支持,我该如何操作?

我需要创建TokenCallable的新实例并获取令牌吗?如果是这样,如何实例化TokenCallable?

TokenCallable是否线程安全?

1个回答

6
您无法直接使用AuthzClient类来执行此操作。但是,您可以使用从org.keycloak.authorization.client.util包中提供的一些低级API,例如Http类。例如:
public AccessTokenResponse refreshToken(String refreshToken) {
    String url = kcProperties.getAuthServerUrl() + "/realms/" + kcProperties.getRealm() + "/protocol/openid-connect/token";
    String clientId = kcProperties.getResource();
    String secret = (String) kcProperties.getCredentials().get("secret");
    Http http = new Http(kcConfig, (params, headers) -> {});

    return http.<AccessTokenResponse>post(url)
            .authentication()
                .client()
            .form()
                .param("grant_type", "refresh_token")
                .param("refresh_token", refreshToken)
                .param("client_id", clientId)
                .param("client_secret", secret)
            .response()
                .json(AccessTokenResponse.class)
            .execute();
}

@Bean
public org.keycloak.authorization.client.Configuration kcConfig() {
    return new org.keycloak.authorization.client.Configuration(
            kcProperties.getAuthServerUrl(),
            kcProperties.getRealm(),
            kcProperties.getResource(),
            kcProperties.getCredentials(),
            null
    );
}

该解决方案完全支持多线程(详见CloseableHttpClient)。


我自己尝试过,已经得到了新的令牌。但是我该如何让应用程序使用新生成的令牌呢? - tony _008
1
@tony_008 我已经更新了答案:你可以将kcConfig注入到你的组件中。 - maslick
2
我认为你误解了我的观点。AuthzClient基本上是Keycloak的REST客户端。我的回答解释了如何使用刷新令牌通过REST从Keycloak服务器获取新令牌。 - maslick
@tony_008,如果你正在使用keycloak-spring-boot-starter,那么一旦你像我上面描述的那样使用AuthzClient刷新令牌,Keycloak适配器将会知道令牌已经被更新。 - maslick
好的,我明白了,那正是我所需要的。不过最后一个问题。你在回答原始问题时提到:“您无法通过AuthzClient库显式执行此操作”。所以你的代码似乎没有使用AuthzClient。这是正确的吗?还是我漏掉了什么?非常感谢你花费的时间,我很感激。 - tony _008
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接