gpt4 book ai didi

java - 使用 Keycloak 保护类型安全的微配置文件 RestClientBuilder

转载 作者:行者123 更新时间:2023-12-01 18:15:00 25 4
gpt4 key购买 nike

我有以下设置:
Keycloak 9.0.0 在端口 8180 上运行
在端口 8080 上运行的 Spring Boot 服务器应用程序
使用 CxfTypeSafeClientBuilder 访问服务器服务的演示客户端应用程序

Keycloak - Spring Boot 交互工作正常,我可以从 Keycloak 接收 token ,并且如果我将其作为 Authorization header 传递,演示服务就会验证该 token 。

我应该如何配置 CxfTypeSafeClientBuilder/RestClientBuilder 来处理从 Keycloak 实例获取的 JWT token ?我是否必须构建自己的 ClientResponseFilter,如果是的话如何处理过期的 token ?
是否有我未找到的现有实现/标准?

JAX-RS Web 服务接口(interface):

@Path("/demo")
public interface IDemoService {

@GET
@Path("/test")
String test();

}

简单的 Spring Security 配置:

http.cors().and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.sessionAuthenticationStrategy(sessionAuthenticationStrategy()).and().authorizeRequests().antMatchers("/**")
.authenticated();

编辑:从服务器获取初始访问和刷新 token 的新解决方法:

AccessTokenResponse tokens = AuthUtil.getAuthTokens("http://localhost:8180/auth", "share-server", "test", "test", "share-server-service-login");
String accessToken = tokens.getToken();
String refreshToken = tokens.getRefreshToken();

客户端执行服务调用,直到 token 过期:

URI apiUri = new URI("http://localhost:8080/services/");
RestClientBuilder client = new CxfTypeSafeClientBuilder().baseUri(apiUri).register(new TokenFilter(accessToken, refreshToken));

IDemoService service = client.build(IDemoService.class);
for (int i = 0; i < 200; i++) {
System.out.println("client: " + new Date() + " " + service.test());
Thread.sleep(10000);
}

TokenFilter 在访问 token 过期之前一直有效:

public static class TokenFilter implements ClientRequestFilter, ClientResponseFilter {

private String accessToken;
private String refreshToken;

public TokenFilter(String accessToken, String refreshToken) {
this.accessToken = accessToken;
this.refreshToken = refreshToken;
}

@Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
if (responseContext.getStatus() == 401 && "invalid_token".equals(responseContext.getStatusInfo().getReasonPhrase())) {
// maybe handle send the refresh token... probalby should be handled earlier using the 'expires' value
}
}

@Override
public void filter(ClientRequestContext requestContext) throws IOException {
if (accessToken != null && !accessToken.isEmpty()) {
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, "Bearer" + " " + accessToken);
}
}
}

最佳答案

找到了一个更好的解决方案,仅依赖于 keycloak-authz-client :

String serverUrl = "http://localhost:8180/auth";
String realm = "share-server";
String clientId = "share-server-service-login";
String clientSecret = "e70752a6-8910-4043-8926-03661f43398c";
String username = "test";
String password = "test";

Map<String, Object> credentials = new HashMap<>();
credentials.put("secret", clientSecret);
Configuration configuration = new Configuration(serverUrl, realm, clientId, credentials, null);
AuthzClient authzClient = AuthzClient.create(configuration);

AuthorizationResource authorizationResource = authzClient.authorization(username, password);

URI apiUri = new URI("http://localhost:8080/services/");
RestClientBuilder client = new CxfTypeSafeClientBuilder().baseUri(apiUri).register(new TokenFilter(authorizationResource));
IDemoService service = client.build(IDemoService.class);
for (int i = 0; i < 200; i++) {
System.out.println("client: " + new Date() + " " + service.test());
Thread.sleep(10000);
}

authorizationResource.authorize() 将在后台使用 org.keycloak.authorization.client.util.TokenCallable.call() 来验证 token 过期时间并自动如有必要,刷新 token 。

so String accessToken = authorize.getToken(); will always be the current valid token.

@Priority(Priorities.AUTHENTICATION)
public static class TokenFilter implements ClientRequestFilter {

private AuthorizationResource authorizationResource;

public TokenFilter(AuthorizationResource authorizationResource) {
this.authorizationResource = authorizationResource;
}

@Override
public void filter(ClientRequestContext requestContext) throws IOException {
AuthorizationResponse authorize = authorizationResource.authorize();
String accessToken = authorize.getToken();
System.out.println(accessToken);
if (accessToken != null && !accessToken.isEmpty()) {
requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, "Bearer" + " " + accessToken);
}
}
}

关于java - 使用 Keycloak 保护类型安全的微配置文件 RestClientBuilder,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60390401/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com