Как обойти страницу входа в систему keycloak и предоставить предложенному клиентом идентификатору Spring Security

Я настроил Spring-безопасность с помощью keycloak, используя функцию клиента Oauth2 в BFF, keycloak будет играть роль idp-брокера, и он успешно настроен с помощью Microsoft (позже мы добавим поддержку для Google, Facebook и т. д.) каждый раз. вещь работает как ожидалось!

в нашем приложении есть требование, чтобы пользователи не попадали на страницу входа в систему keycloak, вместо этого мы добавим специальную кнопку «войти с помощью Micorosoft» (или с помощью его/ее предпочтительного провайдера входа) в наше приложение пользовательского интерфейса, и пользователь будет перенаправлен на страницу входа Microsoft для подключения.

Моя настройка OAuth2 (и она работает):

  • Я использую шаблон BFF с java/spring, используя Spring Security для обработки authN/authZ.
  • BFF настроен как конфиденциальный клиент в keycloak
  • Аутентификация настроена на использование файлов cookie и сеансов на стороне сервера.
  • keycloak используется в качестве брокера idp путем интеграции и настройки внешних idps.
  • Приложение пользовательского интерфейса, которое запускается в браузере и взаимодействует с BFF (в виде статических файлов с nginx)

Вопрос в том, как обойти страницу входа в систему keycloak и перенаправить пользователя непосредственно к выбранному им провайдеру, которого мы уже настроили и поддерживаем? Как мы можем сделать это из системы безопасности srping, чтобы мы могли указать keycloak перенаправить на определенную страницу входа в систему idp?

Что я нашел на данный момент:

  • В keycloak мы можем предоставить дополнительный параметр запроса «kc_idp_hint» в авторизации_endpoint. Я протестировал его, добавив параметр вручную, и он работает, но я не знаю, как это сделать из Spring Security для обработки запрошенного пользователем idp.

Любая помощь, пожалуйста?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
0
0
109
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как обойти страницу входа в Keycloak и предоставить IDP, предложенный клиентом?

Вы уже нашли ответ на этот вопрос: укажите параметр kc_idp_hint в запросе на авторизацию.

Как добавить нестандартный или необязательный параметр в запрос авторизации, созданный клиентом Spring OAuth2 (например, kc_idp_hint для Keycloak, audience для Auth0 и т. д.)?

Это делается с помощью кастома (Server)OAuth2AuthorizationRequestResolver.

Я представлю решения, основанные на регистрации клиента OAuth2 для каждого варианта входа, с примером:

  • «обычный» экран входа в Keycloak, который у вас есть сейчас (это регистрация с default-registration-id в качестве идентификатора)
  • прямой доступ к экрану входа в Google (google-registration-id при условии, что вы указали google IDP в Keycloak)
  • прямой доступ к экрану входа в Facebook (facebook-registration-id при условии, что вы назвали facebook IDP в Keycloak)

Это подразумевает, что свойства конфигурации выглядят примерно так:

oauth2-issuer: change-me
oauth2-client-id: change-me
oauth2-client-secret: change-me
scope: "openid profile email offline_access"

spring:
  security:
    oauth2:
      client:
        provider:
          keycloak:
            issuer-uri: ${oauth2-issuer}
            user-name-attribute: preferred_username
        registration:
          # registration for direct access to Google login page
          google-registration-id:
            provider: keycloak
            client-id: ${oauth2-client-id}
            client-secret: ${oauth2-client-secret}
            authorization-grant-type: authorization_code
            scope: $scope
          # registration for direct access to Facebook login page
          facebook-registration-id:
            provider: keycloak
            client-id: ${oauth2-client-id}
            client-secret: ${oauth2-client-secret}
            authorization-grant-type: authorization_code
            scope: $scope
          # registration for accessing Keycloak login page
          default-registration-id:
            provider: keycloak
            client-id: ${oauth2-client-id}
            client-secret: ${oauth2-client-secret}
            authorization-grant-type: authorization_code
            scope: $scope

В зависимости от того, какую регистрацию клиента OAuth2 активирует интерфейс (путем перенаправления пользователя на конечную точку BFF /oauth2/authorization/{registration-id}), пользователь увидит другой экран входа в систему.

Поскольку я предполагаю, что ваш Spring BFF, настроенный как конфиденциальный клиент OAuth2, является реактивным экземпляром Spring Cloud Gateway, я сосредоточусь на реактивном преобразователе запросов авторизации: ServerOAuth2AuthorizationRequestResolver.

Два варианта в зависимости от того, используете ли вы только spring-boot-starter-oauth2-client или spring-addons-starter-oidc (моя закваска) в дополнение к нему.

1. С spring-addons-starter-oidc

Начнем с простого. Все, что вам нужно в этом случае, это добавить kc_idp_hint для каждого идентификатора регистрации в свойствах приложения:

com:
  c4-soft:
    springaddons:
      oidc:
        client:
          authorization-params:
            google-registration-id:
              kc_idp_hint: google
            facebook-registration-id:
              kc_idp_hint: facebook

2. Всего лишь spring-boot-starter-oauth2-client

В этом случае вам придется самостоятельно написать собственный преобразователь запросов авторизации, а затем настроить с его помощью цепочку фильтров безопасности.

Вот возможный вариант:

@Component
public class KcIdpHintServerOAuth2AuthorizationRequestResolver implements ServerOAuth2AuthorizationRequestResolver {

    private final DefaultServerOAuth2AuthorizationRequestResolver defaultDelegate;
    private final Map<String, ServerOAuth2AuthorizationRequestResolver> authorizationRequestResolversByRegistrationId;

    public KcIdpHintServerOAuth2AuthorizationRequestResolver(ReactiveClientRegistrationRepository clientRegistrationRepository) {
        this.defaultDelegate = new DefaultServerOAuth2AuthorizationRequestResolver(clientRegistrationRepository);

        // Rather than a static conf like that, you might parse a map from custom configuration properties
        this.authorizationRequestResolversByRegistrationId = Map.of(
                "google-registration-id", authorizationRequestResolverWithHintFor(clientRegistrationRepository, "google"),
                "facebook-registration-id", authorizationRequestResolverWithHintFor(clientRegistrationRepository, "facebook"));
    }

    @Override
    public Mono<OAuth2AuthorizationRequest> resolve(ServerWebExchange exchange) {
        return defaultDelegate.resolve(exchange);
    }

    @Override
    public Mono<OAuth2AuthorizationRequest> resolve(ServerWebExchange exchange, String clientRegistrationId) {
        final var delegate = authorizationRequestResolversByRegistrationId.getOrDefault(clientRegistrationId, defaultDelegate);
        return delegate.resolve(exchange, clientRegistrationId);
    }

    private
            ServerOAuth2AuthorizationRequestResolver
            authorizationRequestResolverWithHintFor(ReactiveClientRegistrationRepository clientRegistrationRepository, String hint) {
        final var authorizationRequestResolver = new DefaultServerOAuth2AuthorizationRequestResolver(clientRegistrationRepository);
        authorizationRequestResolver.setAuthorizationRequestCustomizer(
                oauth2AuthorizationRequestBuilder -> oauth2AuthorizationRequestBuilder.additionalParameters(Map.of("kc_idp_hint", hint)));
        return authorizationRequestResolver;
    }

}
@Bean
SecurityWebFilterChain clientSecurityFilterChain(
        ServerHttpSecurity http,
        ServerOAuth2AuthorizationRequestResolver authorizationRequestResolver) {
    http.oauth2Login(oauth2 -> {
        oauth2.authorizationRequestResolver(authorizationRequestResolver);
    });
    ...
    return http.build();
}

Часть безопасности Spring - это та часть, в которой я не уверен, еще не пробовал ваш ответ, но, похоже, она решает мой вариант использования. Спасибо, что нашли время ответить @ch4mp.

Saber Bjeoui 31.05.2024 13:21

Если вы еще не используете «мой» стартер в качестве лучшего друга, вам, вероятно, стоит попробовать. Он решает гораздо больше, чем просто дополнительные параметры запроса авторизации: URI перенаправления входа в систему / выхода из системы, дает выбор статуса HTTP для ответов BFF во время потока кода авторизации, помогает с настройкой защиты CSRF, ... Пример здесь

ch4mp 31.05.2024 19:32

Другие вопросы по теме

Spring Security. Эта страница не работает. Localhost перенаправлял вас слишком много раз. при попытке доступа к localhost:8080 с помощью Spring Security
Почему мой пользователь анонимен после входа в систему по OAuth2 с помощью Spring Boot?
Ошибка происхождения Cors приложения микросервиса Spring Boot
Spring безопасность oauth2Login на основе средства сопоставления запросов
Пытается ли Spring Security авторизовать клиента для общедоступной конечной точки?
Используя Spring Security 6.2.4, но я не могу найти проверку hasScope в HttpSecurity
Spring boot 401 Неавторизованный при почтовом запросе аутентификации
Моя пользовательская страница входа перенаправляется в цикле после обновления до Spring Security 6
Почему запросы POST не работают с использованием аутентификации Spnego/Kerberos с помощью Spring Security Kerberos?
NullPointerException в источнике данных с автоматическим подключением после добавления аннотации безопасности на уровне метода