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 7bb8f6193..a0ad4bd61 100644 --- a/application/src/main/java/run/halo/app/config/WebFluxConfig.java +++ b/application/src/main/java/run/halo/app/config/WebFluxConfig.java @@ -15,6 +15,7 @@ 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; @@ -40,6 +41,8 @@ import run.halo.app.console.WebSocketRequestPredicate; 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 +203,23 @@ public class WebFluxConfig implements WebFluxConfigurer { 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) { + return new AdditionalWebFilterChainProxy(extensionGetter); + } } 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 6d1a5d4ce..17af565dc 100644 --- a/application/src/main/java/run/halo/app/config/WebServerSecurityConfig.java +++ b/application/src/main/java/run/halo/app/config/WebServerSecurityConfig.java @@ -30,9 +30,7 @@ import run.halo.app.core.extension.service.UserService; import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.infra.AnonymousUserConst; 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; @@ -60,7 +58,6 @@ public class WebServerSecurityConfig { RoleService roleService, ObjectProvider securityConfigurers, ServerSecurityContextRepository securityContextRepository, - ExtensionGetter extensionGetter, ReactiveExtensionClient client, PatJwkSupplier patJwkSupplier) { @@ -92,7 +89,7 @@ public class WebServerSecurityConfig { // 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 45095f26f..000000000 --- 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 000000000..7952bc113 --- /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)); + } + +}