From f7767f8e56002c7f7e4bb5a59c19c3d71572178d Mon Sep 17 00:00:00 2001 From: John Niang Date: Thu, 8 Feb 2024 17:48:20 +0800 Subject: [PATCH] Refactor AdditionalWebFilter load Signed-off-by: John Niang --- .../run/halo/app/config/WebFluxConfig.java | 30 +++++++++ .../app/config/WebServerSecurityConfig.java | 3 +- .../DynamicMatcherSecurityWebFilterChain.java | 66 ------------------- .../AdditionalWebFilterChainProxy.java | 35 ++++++++++ ui/.husky/pre-commit | 2 +- 5 files changed, 67 insertions(+), 69 deletions(-) delete mode 100644 application/src/main/java/run/halo/app/security/DynamicMatcherSecurityWebFilterChain.java create mode 100644 application/src/main/java/run/halo/app/webfilter/AdditionalWebFilterChainProxy.java diff --git a/application/src/main/java/run/halo/app/config/WebFluxConfig.java b/application/src/main/java/run/halo/app/config/WebFluxConfig.java index 7bb8f6193ab..99060d1c511 100644 --- a/application/src/main/java/run/halo/app/config/WebFluxConfig.java +++ b/application/src/main/java/run/halo/app/config/WebFluxConfig.java @@ -8,13 +8,16 @@ import static run.halo.app.infra.utils.FileUtils.checkDirectoryTraversal; import com.fasterxml.jackson.databind.ObjectMapper; +import io.micrometer.observation.ObservationRegistry; import java.util.List; import java.util.Objects; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.web.WebProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; import org.springframework.http.CacheControl; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; @@ -24,6 +27,7 @@ import org.springframework.http.codec.json.Jackson2JsonDecoder; import org.springframework.http.codec.json.Jackson2JsonEncoder; import org.springframework.lang.NonNull; +import org.springframework.security.web.server.ObservationWebFilterChainDecorator; import org.springframework.web.reactive.config.ResourceHandlerRegistration; import org.springframework.web.reactive.config.ResourceHandlerRegistry; import org.springframework.web.reactive.config.WebFluxConfigurer; @@ -40,6 +44,8 @@ import run.halo.app.core.extension.endpoint.CustomEndpoint; import run.halo.app.core.extension.endpoint.CustomEndpointsBuilder; import run.halo.app.infra.properties.HaloProperties; +import run.halo.app.plugin.extensionpoint.ExtensionGetter; +import run.halo.app.webfilter.AdditionalWebFilterChainProxy; @Configuration public class WebFluxConfig implements WebFluxConfigurer { @@ -200,4 +206,28 @@ ProxyFilter consoleProxyFilter() { ProxyFilter ucProxyFilter() { return new ProxyFilter("/uc/**", haloProp.getUc().getProxy()); } + + /** + * Create a WebFilterChainProxy for all AdditionalWebFilters. + * + *

The reason why the order is -101 is that the current + * AdditionalWebFilterChainProxy should be executed before WebFilterChainProxy + * and the order of WebFilterChainProxy is -100. + * + *

See {@code org.springframework.security.config.annotation.web.reactive + * .WebFluxSecurityConfiguration#WEB_FILTER_CHAIN_FILTER_ORDER} for more + * + * @param extensionGetter extension getter. + * @return additional web filter chain proxy. + */ + @Bean + @Order(-101) + AdditionalWebFilterChainProxy additionalWebFilterChainProxy(ExtensionGetter extensionGetter, + ObjectProvider observationRegistry) { + var chainProxy = new AdditionalWebFilterChainProxy(extensionGetter); + observationRegistry.ifUnique(registry -> + chainProxy.setFilterChainDecorator(new ObservationWebFilterChainDecorator(registry)) + ); + return chainProxy; + } } diff --git a/application/src/main/java/run/halo/app/config/WebServerSecurityConfig.java b/application/src/main/java/run/halo/app/config/WebServerSecurityConfig.java index 6d1a5d4ce4d..cbc6e647238 100644 --- a/application/src/main/java/run/halo/app/config/WebServerSecurityConfig.java +++ b/application/src/main/java/run/halo/app/config/WebServerSecurityConfig.java @@ -32,7 +32,6 @@ import run.halo.app.infra.properties.HaloProperties; import run.halo.app.plugin.extensionpoint.ExtensionGetter; import run.halo.app.security.DefaultUserDetailService; -import run.halo.app.security.DynamicMatcherSecurityWebFilterChain; import run.halo.app.security.authentication.SecurityConfigurer; import run.halo.app.security.authentication.login.CryptoService; import run.halo.app.security.authentication.login.PublicKeyRouteBuilder; @@ -92,7 +91,7 @@ SecurityWebFilterChain apiFilterChain(ServerHttpSecurity http, // Integrate with other configurers separately securityConfigurers.orderedStream() .forEach(securityConfigurer -> securityConfigurer.configure(http)); - return new DynamicMatcherSecurityWebFilterChain(extensionGetter, http.build()); + return http.build(); } @Bean diff --git a/application/src/main/java/run/halo/app/security/DynamicMatcherSecurityWebFilterChain.java b/application/src/main/java/run/halo/app/security/DynamicMatcherSecurityWebFilterChain.java deleted file mode 100644 index 45095f26f44..00000000000 --- a/application/src/main/java/run/halo/app/security/DynamicMatcherSecurityWebFilterChain.java +++ /dev/null @@ -1,66 +0,0 @@ -package run.halo.app.security; - -import org.springframework.core.Ordered; -import org.springframework.core.annotation.AnnotationAwareOrderComparator; -import org.springframework.lang.NonNull; -import org.springframework.security.web.server.SecurityWebFilterChain; -import org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher; -import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.WebFilter; -import org.springframework.web.server.WebFilterChain; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import run.halo.app.plugin.extensionpoint.ExtensionGetter; - -/** - * A {@link SecurityWebFilterChain} that leverages a {@link ServerWebExchangeMatcher} to - * determine which {@link WebFilter} to execute. - * - * @author guqing - * @since 2.4.0 - */ -public class DynamicMatcherSecurityWebFilterChain implements SecurityWebFilterChain { - - private final SecurityWebFilterChain delegate; - - private final ExtensionGetter extensionGetter; - - public DynamicMatcherSecurityWebFilterChain(ExtensionGetter extensionGetter, - SecurityWebFilterChain delegate) { - this.delegate = delegate; - this.extensionGetter = extensionGetter; - } - - @Override - public Mono matches(ServerWebExchange exchange) { - return delegate.matches(exchange); - } - - @Override - public Flux getWebFilters() { - return Flux.merge(delegate.getWebFilters(), getAdditionalFilters()) - .sort(new AnnotationAwareOrderComparator()); - } - - private Flux getAdditionalFilters() { - return extensionGetter.getEnabledExtensionByDefinition(AdditionalWebFilter.class) - .map(additionalWebFilter -> new OrderedWebFilter(additionalWebFilter, - additionalWebFilter.getOrder()) - ); - } - - private record OrderedWebFilter(WebFilter webFilter, int order) implements WebFilter, Ordered { - - @Override - @NonNull - public Mono filter(@NonNull ServerWebExchange exchange, - @NonNull WebFilterChain chain) { - return this.webFilter.filter(exchange, chain); - } - - @Override - public int getOrder() { - return this.order; - } - } -} diff --git a/application/src/main/java/run/halo/app/webfilter/AdditionalWebFilterChainProxy.java b/application/src/main/java/run/halo/app/webfilter/AdditionalWebFilterChainProxy.java new file mode 100644 index 00000000000..7952bc113df --- /dev/null +++ b/application/src/main/java/run/halo/app/webfilter/AdditionalWebFilterChainProxy.java @@ -0,0 +1,35 @@ +package run.halo.app.webfilter; + +import lombok.Setter; +import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.security.web.server.WebFilterChainProxy; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Mono; +import run.halo.app.plugin.extensionpoint.ExtensionGetter; +import run.halo.app.security.AdditionalWebFilter; + +public class AdditionalWebFilterChainProxy implements WebFilter { + + private final ExtensionGetter extensionGetter; + + @Setter + private WebFilterChainProxy.WebFilterChainDecorator filterChainDecorator; + + public AdditionalWebFilterChainProxy(ExtensionGetter extensionGetter) { + this.extensionGetter = extensionGetter; + this.filterChainDecorator = new WebFilterChainProxy.DefaultWebFilterChainDecorator(); + } + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + return extensionGetter.getEnabledExtensionByDefinition(AdditionalWebFilter.class) + .sort(AnnotationAwareOrderComparator.INSTANCE) + .cast(WebFilter.class) + .collectList() + .map(filters -> filterChainDecorator.decorate(chain, filters)) + .flatMap(decoratedChain -> decoratedChain.filter(exchange)); + } + +} diff --git a/ui/.husky/pre-commit b/ui/.husky/pre-commit index 47209831459..f2c634340db 100755 --- a/ui/.husky/pre-commit +++ b/ui/.husky/pre-commit @@ -1,4 +1,4 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -cd console && pnpm exec lint-staged +cd ui && pnpm exec lint-staged