У меня есть следующие настройки: Keycloak 9.0.0 работает на порту 8180 Серверное приложение Spring Boot, работающее на порте 8080 Демо-клиентское приложение, использующее CxfTypeSafeClientBuilder
для доступа к сервису сервера
Взаимодействие Keycloak - Spring Boot работает нормально, и я могу получать токены от Keycloak, и демонстрационный сервис проверяет токен, если я передаю его как заголовок Authorization
.
Как настроить CxfTypeSafeClientBuilder
/ RestClientBuilder
для обработки токенов JWT, которые я получаю из экземпляра Keycloak? Нужно ли мне создавать свои собственные ClientResponseFilter
, если да, то как обращаться с токенами с истекшим сроком? Существуют ли какие-либо реализации / стандарты, которые я не нашел?
Интерфейс веб-сервиса JAX-RS:
@Path("/demo")
public interface IDemoService {
@GET
@Path("/test")
String test();
}
Конфигурация Simple Spring Security:
http.cors().and().csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.sessionAuthenticationStrategy(sessionAuthenticationStrategy()).and().authorizeRequests().antMatchers("/**")
.authenticated();
РЕДАКТИРОВАТЬ: новый обходной путь для получения начального доступа и обновления токена sh с сервера:
AccessTokenResponse tokens = AuthUtil.getAuthTokens("http://localhost:8180/auth", "share-server", "test", "test", "share-server-service-login");
String accessToken = tokens.getToken();
String refreshToken = tokens.getRefreshToken();
Клиент, выполняющий сервисные вызовы до истечения срока действия токена:
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, который работает до истечения срока действия токена доступа:
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);
}
}
}