【问题标题】:Java client to refresh keycloak tokenJava客户端刷新keycloak令牌
【发布时间】:2018-12-08 00:53:45
【问题描述】:

想象一下,

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

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

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

  • service-2-user

做service to service调用,即: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

在 keyclock 中设置 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 线程安全吗?

【问题讨论】:

    标签: spring-boot spring-security keycloak keycloak-services


    【解决方案1】:

    您不能通过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)。

    【讨论】:

    • 嗨,这看起来很有帮助。一个问题;通过发出此令牌刷新请求,是否会将“原始 access_token”替换为此处创建的新 access_token 作为副作用?或者此代码只会生成新的 access_token(但替换“旧 access_token”仍需要作为第二步手动完成)?谢谢!
    • 我自己试过了,我得到了新的令牌。但是如何让应用程序使用新生成的令牌? thc
    • @tony_008 我已经更新了答案:您可以将 kcConfig 注入到您的组件中。
    • 感谢您抽出时间@maslick。我能够生成令牌。我遇到的问题是我无法覆盖spring安全连接器向keycloack auth服务器请求的access_token(和refresh_token)。我可以生成令牌,但我不能告诉我的应用程序使用新令牌,应用程序继续使用旧令牌。您使用的是 Spring-boot 适配器 + Spring 安全性吗?关于如何告诉应用开始使用新创建的令牌而不是旧令牌的任何反馈?
    • 我想你误解了我的意思。 AuthzClient 基本上是 Keycloak 的 REST 客户端。我的回答解释了如何使用刷新令牌通过 REST 从 Keycloak 服务器获取新令牌。
    猜你喜欢
    • 2019-12-30
    • 2020-02-25
    • 2013-02-03
    • 2020-08-27
    • 1970-01-01
    • 1970-01-01
    • 2021-01-22
    • 2012-06-25
    • 2017-10-27
    相关资源
    最近更新 更多