РЕДАКТИРОВАТЬ: вот окончательное решение: Итак, вот как я это сделал:
Цель: удалить 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).