Как настроить только на предъявителя = true при использовании spring-boot-starter-oauth2-client

#spring-boot #spring-security #oauth #keycloak #api-gateway

#spring-boot #spring-безопасность #oauth #скрытый ключ #api-шлюз

Вопрос:

Я пытаюсь настроить аутентификацию o auth2 в spring cloud gateway для моих rest api с помощью keycloak. keyclcoak перенаправляет мой запрос на страницу входа при передаче токена доступа в качестве токена предъявителя. Во многих местах я нашел решение для этого — установить bearer-only = true в адаптере keycloak. где установить это при использовании spring-boot-starter-oauth2-client. Я не могу использовать keycloak-spring-boot-starter, чтобы установить это в application.yml

Спасибо

Комментарии:

1. Что заставляет вас использовать spring-security-oauth2-client? Клиентский модуль предназначен для получения токена через поток предоставления OAuth 2.0. Как создаваемый вами шлюз узнает, что это за токен? Если он просто передается шлюзу в Authorization заголовке, то spring-security-oauth2-resource-server — это то, что это делает.

2. @jzhaux Я пытаюсь выполнить аутентификацию в шлюзе для своих служб, работающих за ним. Я настроил сервер keycloack с областью, пользователями и ролями, с моей конечной точкой токена я могу получить токен oauth2. Я хочу передать этот токен с запросом и пройти аутентификацию в шлюзе. Я новичок в этой spring framework.

3. Спасибо, это полезно. Как вы передаете токен шлюзу? Передает ли вызывающий его шлюзу Authorization , например, в заголовке?

Ответ №1:

У меня был тот же вопрос, что и у вас. Не найдя ответа, я разработал фильтр с легким клиентом keycloak, который вызывает конечную точку для проверки keycloak для проверки токена

клиент:

 public class KeycloakClient {

private final KeycloakConfigurationProperties kcProperties;
private final WebClient client;

public KeycloakClient(final KeycloakConfigurationProperties keycloakConfigurationProperties) {
    this.kcProperties = keycloakConfigurationProperties;
    this.client = WebClient.builder()
                           .baseUrl(keycloakConfigurationProperties.getAuth_server_url())
                           .filter(logRequest())
                           .build();
}

public Mono<Boolean> validateBearerToken(String bearerToken) {
    //todo: improve error management
    return prepareAndRunRequest(bearerToken).retrieve()
                                            .bodyToMono(KeycloakValidationResponse.class)
                                            .flatMap(response -> Mono.just(response.getActive()))
                                            .onErrorResume(WebClientResponseException.class,
                                                           ex -> Mono.just(false));
}

private WebClient.RequestHeadersSpec<?> prepareAndRunRequest(String bearerToken) {

    return client.post()
                 .uri(uriBuilder -> uriBuilder.path("/auth/realms/")
                                              .path(kcProperties.getRealm())
                                              .path("/protocol/openid-connect/token/introspect")
                                              .build())
                 .contentType(MediaType.APPLICATION_JSON)
                 .body(BodyInserters.fromFormData("client_id", kcProperties.getResource())
                                    .with("client_secret", kcProperties.getCredentials_secret())
   
  

фильтр:

 public class ValidationTokenGatewayFilterFactory extends AbstractGatewayFilterFactory<ValidationTokenGatewayFilterFactory.Config> {

private final KeycloakClient client;

public ValidationTokenGatewayFilterFactory(KeycloakClient client) {
    super(Config.class);
    this.client = client;
}

@Override
public GatewayFilter apply(Config config) {
    return (exchange, chain) -> {

        String token = exchange.getRequest()
                               .getHeaders()
                               .get(AUTHORIZATION)
                               .get(0);

        token = token.substring(7);

        log.trace("-- ValidationToken(): token={}", token);

        return client.validateBearerToken(token)
                     .flatMap(validated -> {
                         if (validated) {
                             log.debug("-- ValidationToken(): Token valid");
                             return chain.filter(exchange);
                         } else {
                             log.debug("-- ValidationToken(): Token invalid");
                             exchange.getResponse()
                                     .setStatusCode(HttpStatus.UNAUTHORIZED);

                             return exchange.getResponse()
                                            .setComplete();
                         }
                     });
    };
}

public static class Config {
}
  

}

Вы можете найти полный пример здесь: https://gitlab.com/-/snippets/2105967