模块化 Spring Security SecurityWebFilterChain

我们的 Spring Security 配置文件越来越大,我们想将它分解成更小的部分。现在我们有以下内容:


public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {

    http.securityMatcher(ServerWebExchangeMatchers.pathMatchers("/api/**"))

            .authenticationManager(this.authenticationManager);


    http.authorizeExchange()

            .pathMatchers(HttpMethod.GET, "/api/serviceA/**")

            .hasAuthority("PROP_A");


    http.authorizeExchange()

            .pathMatchers(HttpMethod.GET, "/api/serviceB/**")

            .hasAuthority("PROP_B");


    http.authorizeExchange().pathMatchers(HttpMethod.POST, "/api/login", "/api/logout", "/api/forgotPassword", "/api/confirmForgotPassword").permitAll();


    http.csrf()

            .disable()

            .formLogin()

            .authenticationEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED))

            .requiresAuthenticationMatcher(

                    ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, "/api/login"))

            .authenticationFailureHandler(CustomSpringSecurity::onAuthenticationFailure)

            .authenticationSuccessHandler(CustomSpringSecurity::onAuthenticationSuccess)

            .and()

            .logout()

            .logoutUrl("/api/logout")

            .logoutSuccessHandler(new CustomLogoutSuccessHandler(HttpStatus.OK));


    final SecurityWebFilterChain build = http.build();


我们想用它securityMatcher来突破/api/seviceA/**并/api/seviceB/**拥有自己的SecurityWebFilterChain @Beans。


但是,我们遇到的问题是配置中存在额外的配置。我们希望最终结果如下所示。


    public SecurityWebFilterChain securityWebFilterChainForServiceA(ServerHttpSecurity http) {

        http.securityMatcher(ServerWebExchangeMatchers.pathMatchers("/api/serviceA/**"));


        http.authorizeExchange()

                .pathMatchers(HttpMethod.GET, "/api/serviceA/**")

                .hasAuthority("PROP_A");

        return http.build();

    }

我们希望端点的所有其他配置都是隐式的。


Spring Security 怎么可能做这样的模块化呢?


眼眸繁星
浏览 338回答 1
1回答

慕容3067478

您可以像这样指定一个接口:&nbsp; &nbsp; public interface HttpSecurityConfig {&nbsp; &nbsp; &nbsp; &nbsp; Consumer<ServerHttpSecurity> configuration();&nbsp; &nbsp; }然后创建一个类,为每个端点实现它,您可以将其作为 bean 注入:&nbsp; &nbsp; @Component&nbsp; &nbsp; public class ServiceASecurityConfig implements HttpSecurityConfig {&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public Consumer<ServerHttpSecurity> configuration() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return (http) -> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; http.authorizeExchange()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .pathMatchers(HttpMethod.GET, "/api/serviceA/**")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .hasAuthority("PROP_A");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; @Component&nbsp; &nbsp; public class ServiceBSecurityConfig implements HttpSecurityConfig {&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public Consumer<ServerHttpSecurity> configuration() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return (http) -> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; http.authorizeExchange()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .pathMatchers(HttpMethod.GET, "/api/serviceB/**")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .hasAuthority("PROP_B");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }最后修改你的SecurityWebFilterChain所以它注入所有类型的beanHttpSecurityConfig并应用配置,就像这样:public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http, final List<HttpSecurityConfig> httpConfigurations) {&nbsp; &nbsp; http.securityMatcher(ServerWebExchangeMatchers.pathMatchers("/api/**"))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .authenticationManager(this.authenticationManager);&nbsp; &nbsp; // This line replaces the individual configurations in your original question&nbsp; &nbsp; httpConfigurations.forEach(config -> config.configuration().accept(http));&nbsp; &nbsp; http.authorizeExchange().pathMatchers(HttpMethod.POST, "/api/login", "/api/logout", "/api/forgotPassword", "/api/confirmForgotPassword").permitAll();&nbsp; &nbsp; http.csrf()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .disable()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .formLogin()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .authenticationEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .requiresAuthenticationMatcher(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, "/api/login"))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .authenticationFailureHandler(CustomSpringSecurity::onAuthenticationFailure)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .authenticationSuccessHandler(CustomSpringSecurity::onAuthenticationSuccess)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .and()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .logout()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .logoutUrl("/api/logout")&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .logoutSuccessHandler(new CustomLogoutSuccessHandler(HttpStatus.OK));&nbsp; &nbsp; final SecurityWebFilterChain build = http.build();&nbsp; &nbsp; build&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .getWebFilters()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .collectList()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .subscribe(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; webFilters -> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (WebFilter filter : webFilters) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (filter instanceof AuthenticationWebFilter) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AuthenticationWebFilter awf = (AuthenticationWebFilter) filter;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; awf.setServerAuthenticationConverter(CustomSpringSecurity::convert);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; return build;}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java