Изменение порядка Spring Security WebFilter - PullRequest
0 голосов
/ 04 октября 2018

Изменение порядка Spring Security WebFilter

У меня есть API-шлюз, реализованный с использованием Spring Cloud Gateway, который использует Spring Security.Spring Security для WebFlux реализован как WebFilter в самом начале цепочки фильтров.Таким образом, после успешной аутентификации запрос будет перенаправлен в RoutePredicateHandlerMapping Spring Cloud Gateway, который попытается определить назначение на основе шаблона URL-адреса, а затем перейдет к FilteringWebHandler для выполнения других фильтров Spring Cloud Gateway.

Моя проблема заключается в следующем: я реализовал настроенный алгоритм аутентификации, который использует строку запроса и переменные заголовка в качестве учетных данных для аутентификации в соответствии с требованиями проекта, и это работает без каких-либо проблем.Проблема возникла, когда нам нужно было добавить небольшую настройку для алгоритма аутентификации, который не зависит от пути.Когда запрос достигает WebFilter Spring Security, сопоставление с образцом еще не выполнено, поэтому я не знаю, на какое приложение он указывает, например:

app1:

-Path: / app1/ **

app2:

-Path: / app2 / **

Это означает, что вместо аутентификации -> сопоставление маршрута -> фильтрация веб-обработчика я должен сделатьотображение маршрута -> аутентификация -> фильтрация веб-обработчика.Не то, чтобы эти три компонента не были похожи, один из них - фильтр, другой - маппер, а последний - веб-обработчик.Теперь я знаю, как их настроить, но проблема в том, что я не знаю, как перехватить процесс построения сервера Netty, чтобы изменить порядок этих операций.Мне нужно дождаться окончания процесса сборки и изменить содержимое сервера, прежде чем он запустится.Как я могу это сделать?

Ответы [ 2 ]

0 голосов
/ 05 октября 2018

РЕДАКТИРОВАТЬ: вот окончательное решение: Итак, вот как я это сделал:

Цель: удалить WebFilter из Spring Security из HttpHandler по умолчанию и вставить его между RoutePredicateRouteMapping и FilteringWebHandler Spring Cloud Gateway

Почему: потому что мне нужно знать Идентификатор приложения, пока я выполняю свой процесс аутентификации.Этот идентификатор приложения присоединяется к запросу с помощью RoutePredicateRouteMapping путем сопоставления URL-адреса запроса с предварительно определенным списком.

Как я это сделал: 1- Удаление WebFilter из Spring Security Я создал бин HttpHandler, который вызывает по умолчаниюWebHttpHandlerBuilder, а затем настроить фильтры.В качестве бонуса я удалил ненужные фильтры, чтобы повысить производительность моего шлюза API

@Bean
public HttpHandler httpHandler() {
    WebHttpHandlerBuilder webHttpHandlerBuilder = WebHttpHandlerBuilder.applicationContext(this.applicationContext);

    MyAuthenticationHandlerAdapter myAuthenticationHandlerAdapter = this.applicationContext.getBean(MY_AUTHENTICATED_HANDLER_BEAN_NAME, MyAuthenticationHandlerAdapter.class);

    webHttpHandlerBuilder
            .filters(filters ->
                    myAuthenticationHandlerAdapter.setSecurityFilter(
                            Collections.singletonList(filters.stream().filter(f -> f instanceof WebFilterChainProxy).map(f -> (WebFilterChainProxy) f).findFirst().orElse(null))
                    )
            );

    return webHttpHandlerBuilder.filters(filters -> filters
            .removeIf(f -> f instanceof WebFilterChainProxy || f instanceof WeightCalculatorWebFilter || f instanceof OrderedHiddenHttpMethodFilter))
            .build();
}

2 - Оборачивание FilteringWebHandler Spring Cloud Gateway с FilteringWebHandler от Spring Web с добавленным WebFilter. Я создал свой собственный HandlerAdapter, который будет соответствоватьпротив FilteringWebHandler от Spring Cloud Gateway и оберните его с помощью FilteringWebHandler от Spring Web плюс фильтр безопасности, который я извлек на первом шаге

@Bean
public MyAuthenticationHandlerAdapter myAuthenticationHandlerAdapter() {
    return new MyAuthenticationHandlerAdapter();
}

public class MyAuthenticationHandlerAdapter implements HandlerAdapter {
    @Setter
    private List<WebFilter> securityFilter = new ArrayList<>();


    @Override
    public boolean supports(Object handler) {
        return handler instanceof FilteringWebHandler;
    }

    @Override
    public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
        org.springframework.web.server.handler.FilteringWebHandler filteringWebHandler = new org.springframework.web.server.handler.FilteringWebHandler((WebHandler) handler, securityFilter);
        Mono<Void> mono = filteringWebHandler.handle(exchange);
        return mono.then(Mono.empty());
    }
}

Таким образом, я смогу добиться более высокой производительности с помощью высоко настроенного конвейера HttpHandler, который я считаю будущимproof

END EDIT

Spring Security для WebFlux реализован в виде WebFilter, который выполняется почти сразу после получения запроса.Я реализовал пользовательский конвертер аутентификации и менеджер аутентификации, который извлекал бы некоторые переменные из заголовка и URL и использовал их для аутентификации.Это работает без каких-либо проблем.

Теперь мне нужно было добавить еще одну переменную, взятую из RoutePredicateRouteMapping, прежде чем будет выполнена аутентификация.Что мне нужно, так это удалить WebFilter (называемый WebFilterChainProxy) из его текущей позиции и поместить его между RoutePredicateRouteMapping и FilteringWeHandler.

Вот как происходит процесс по умолчанию:

ChannelOperations вызывает ReactorHttpHandlerAdapterкоторый вызывает HttpWebHandlerAdapter, ExceptionHandlingWebHandler, а затем org.springframework.web.server.handler.FilterWebHandler.

Этот WebHandler будет вызывать свои фильтры и затем вызывать DispatchHandler.Одним из таких фильтров является WebFilterChainProxy, который выполняет аутентификацию для Spring Security.Итак, первым шагом является удаление фильтра отсюда.

Теперь DispatchHandler, который вызывается после того, как фильтры вызовут RoutePredicateHandlerMapping, который проанализирует маршруты и даст мне нужный мне идентификатор маршрута, а затем вызоветorg.springframework.cloud.gateway.handler.FilteringHandler (это не тот же FilteringHandler выше), который, в свою очередь, будет вызывать другие фильтры Spring Cloud Gateway.Здесь я хочу вызвать фильтр после RoutePredicatehandlerMapping и перед org.springframework.cloud.gateway.handler.FilteringHandler.То, что я закончил, было следующим:

Я создал и WebHttpHandlerBuilder, который удалит WebFilterChainProxy и передаст его в качестве параметра настроенному DispatcherHandler.Теперь, когда фильтр удален, запрос пройдет первые уровни без аутентификации.В моем настроенном DispatcherHandler я бы вызвал RoutePredicateHandlerMapping и затем передал переменную exchange в WebFilterChainProxy, чтобы выполнить аутентификацию, прежде чем передать ее в org.springframework.cloud.gateway.handler.FilteringHandler, который работал отлично!Я все еще думаю, что перерабатывал это и надеюсь, что есть способ сделать это, используя аннотации и компоненты конфигурации вместо всех этих настраиваемых классов (WebHttpHandlerBuilder и DispatcherHandler).

0 голосов
/ 04 октября 2018

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

Также, , пожалуйста, не пересылайте , команда Spring активно отслеживает StackOverflow.

...