Spring Cloud Gateway перенаправляет на страницу входа в Keycloak, хотя токен Bearer установлен

Я использую настройку с Keycloak в качестве поставщика удостоверений, Spring Cloud Gateway в качестве шлюза API и нескольких микросервисов. Я могу получить JWT через свой шлюз (перенаправление на Keycloak) через http://localhost:8050/auth/realms/dev/protocol/openid-connect/token.

Я могу использовать JWT для доступа к ресурсу, непосредственно расположенному на сервере Keycloak (например, http://localhost:8080/auth/admin/realms/dev/users). Но когда я хочу использовать шлюз для ретрансляции меня на тот же ресурс (http://localhost:8050/auth/admin/realms/dev/users), я получаю форму входа Keycloak в качестве ответа.

Я пришел к выводу, что в моем приложении Spring Cloud Gateway должна быть неправильная конфигурация.

Это конфигурация безопасности на шлюзе:

@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http, ReactiveClientRegistrationRepository clientRegistrationRepository) {

        // Authenticate through configured OpenID Provider
        http.oauth2Login();

        // Also logout at the OpenID Connect provider
        http.logout(logout -> logout.logoutSuccessHandler(
                new OidcClientInitiatedServerLogoutSuccessHandler(clientRegistrationRepository)));

        //Exclude /auth from authentication
        http.authorizeExchange().pathMatchers("/auth/realms/ahearo/protocol/openid-connect/token").permitAll();

        // Require authentication for all requests
        http.authorizeExchange().anyExchange().authenticated();

        // Allow showing /home within a frame
        http.headers().frameOptions().mode(Mode.SAMEORIGIN);

        // Disable CSRF in the gateway to prevent conflicts with proxied service CSRF
        http.csrf().disable();
        return http.build();
    }
}

Это мой application.yaml в шлюзе:

spring:
  application:
    name: gw-service
  cloud:
    gateway:
      default-filters:
        - TokenRelay
      discovery:
        locator:
          lower-case-service-id: true
          enabled: true
      routes:
        - id: auth
          uri: http://localhost:8080
          predicates:
            - Path=/auth/**

  security:
    oauth2:
      client:
        registration:
          keycloak:
            client-id: 'api-gw'
            client-secret: 'not-relevant-but-correct'
            authorizationGrantType: authorization_code
            redirect-uri: '{baseUrl}/login/oauth2/code/{registrationId}'
            scope: openid,profile,email,resource.read
        provider:
          keycloak:
            issuerUri: http://localhost:8080/auth/realms/dev
            user-name-attribute: preferred_username

server:
  port: 8050
eureka:
  client:
    service-url:
      default-zone: http://localhost:8761/eureka
    register-with-eureka: true
    fetch-registry: true

Как я могу сделать так, чтобы шлюз знал, что пользователь аутентифицирован (с помощью JWT), и не перенаправлял меня на страницу входа?


person Felix    schedule 23.06.2020    source источник
comment
не могли бы вы посоветовать, как вы реализовали это в обход страницы входа?   -  person Jacob    schedule 11.11.2020
comment
измените это как на: authorization-grant-type: authorization_code   -  person mtebong    schedule 13.01.2021
comment
Удалось ли вам обойти страницу входа? если да, поделитесь с нами, как?   -  person user585014    schedule 24.02.2021


Ответы (2)


Если вы хотите делать запросы к Spring Gateway с токеном доступа, вам необходимо сделать его сервером ресурсов. Добавьте следующее:

pom.xml

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>

application.yml

  security:
    oauth2:
      resourceserver:
        jwt:
          issuer-uri: https://.../auth/realms/...

SecurityConfiguration.java

@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http,
                                                        ReactiveClientRegistrationRepository clientRegistrationRepository) {
    // Authenticate through configured OpenID Provider
    http.oauth2Login();
    // Also logout at the OpenID Connect provider
    http.logout(logout -> logout.logoutSuccessHandler(
            new OidcClientInitiatedServerLogoutSuccessHandler(clientRegistrationRepository)));
    // Require authentication for all requests
    http.authorizeExchange().anyExchange().authenticated();

    http.oauth2ResourceServer().jwt();

    // Allow showing /home within a frame
    http.headers().frameOptions().mode(Mode.SAMEORIGIN);
    // Disable CSRF in the gateway to prevent conflicts with proxied service CSRF
    http.csrf().disable();
    return http.build();
}
person Dmitri Ciornii    schedule 02.04.2021
comment
Не могли бы вы направить меня сюда - github.com/SaiUpadhyayula/springboot-microservices-project /? Пожалуйста, посмотрите самые последние комментарии - person Pra_A; 02.06.2021

Я обошел проблему, связавшись напрямую с Keycloak, не передавая ему запросы через Spring Cloud Gateway.

На самом деле это не обходной путь, но на самом деле это лучшая практика / полностью нормально, насколько я понимаю.

person Felix    schedule 24.02.2021
comment
Не могли бы вы поделиться исходным кодом? - person Pra_A; 02.06.2021
comment
Код не нужен, просто обратитесь к серверу Keycloak напрямую. Поэтому вместо api.domain.com (чтобы API перенаправлял ваш запрос в Keycloak) используйте keycloak.domain.com (чтобы напрямую отправить запрос экземпляру Keycloak). - person Felix; 07.06.2021