基于pathmatcher添加多个spring安全配置

8aqjt8rx  于 2021-07-13  发布在  Java
关注(0)|答案(2)|浏览(324)

我试图设置多个安全配置,将使用不同的 SecurityApiKeyFilter 基于 pathMatchers ,现在我只有2个。一个适用于所有url,另一个只适用于包含 admin . 最初,您被设置为访客,之后,我们将尝试基于apikey对您进行授权。然而,我真的不能让它到达第二个 SecurityWebFilterChain 配置。即使 pathMatcher 设置为这样。

@Bean
@Order(1)
public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http, 
                                                        ClientService clientService) {
    SecurityWebFilterChain filterChain = http.authorizeExchange()
            .pathMatchers(HttpMethod.GET, "/").permitAll()
            .pathMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .pathMatchers("/**").permitAll()
            .anyExchange().authenticated().and()
            .anonymous().principal("guest").and()
            .addFilterBefore(new SecurityApiKeyFilter(clientService), SecurityWebFiltersOrder.AUTHENTICATION)
            .oauth2ResourceServer().jwt()
            .jwtDecoder(new NimbusReactiveJwtDecoder("/.well-known/jwks.json"))
            .and()
            .and().build();

    return filterChain;
}

@Bean
@Order(2)
public SecurityWebFilterChain sdkJsWebFilterChain(ServerHttpSecurity http,
                                                      ClientService clientService) {
    SecurityWebFilterChain filterChain = http.authorizeExchange()
        .pathMatchers(HttpMethod.OPTIONS, "**/admin/**").permitAll()
        .pathMatchers("**/admin/**").permitAll()
        .anyExchange().authenticated().and()
        .anonymous().principal("guest").and()
        .addFilterBefore(new Admin.SecurityApiKeyFilter(clientService),
            SecurityWebFiltersOrder.AUTHENTICATION)
        .oauth2ResourceServer().jwt()
        .jwtDecoder(new NimbusReactiveJwtDecoder("/.well-known/jwks.json"))
        .and()
        .and().build();

    return filterChain;
}

谢谢。

bksxznpy

bksxznpy1#

我猜React应用程序和servlet应用程序的行为是一样的。
您的第二个安全过滤器链不会被执行,因为只有第一个匹配的安全过滤器链会被调用,请参见9.4。安全筛选器链:
9.4. 安全过滤器链
[...]
事实上, FilterChainProxy 可用于确定 SecurityFilterChain 应该使用。这允许为应用程序的不同部分提供完全独立的配置。

在多重安全过滤器链图中 FilterChainProxy 决定哪个 SecurityFilterChain 应该使用。只有第一个 SecurityFilterChain 将调用匹配项。如果 /api/messages/ 请求时,它将首先匹配 SecurityFilterChain0 的模式 /api/** ,仅此而已 SecurityFilterChain0 即使它也匹配 SecurityFilterChainn . 如果 /messages/ 是请求的,它在上不匹配 SecurityFilterChain0 的模式 /api/** ,所以 FilterChainProxy 将继续尝试每个 SecurityFilterChain . 假设没有其他人, SecurityFilterChain 示例匹配 SecurityFilterChainn 将被调用。

u1ehiz5o

u1ehiz5o2#

我也发现这是非常有用的,如果有人正在寻找其他类型的解决方案,它不是在java,但你会得到要点。

class SecurityConfig {

@Bean
fun getReactiveAuthenticationManager(): ReactiveAuthenticationManager {
    return ReactiveAuthenticationManager { authentication ->
        // simply return the authentication assuming the authentication was already verified in the converter
        Mono.justOrEmpty(authentication)
    }
}

companion object {
    const val ADMIN_RESOURCE_A = "ADMIN_RESOURCE_A"
    const val ADMIN_RESOURCE_B = "ADMIN_RESOURCE_B"
}

@Bean
fun springSecurityFilterChain(http: ServerHttpSecurity,
                              @Qualifier("authFilterResourceA")
                              authFilterResourceA: AuthenticationWebFilter,
                              @Qualifier("authFilterResourceB")
                              authFilterResourceB: AuthenticationWebFilter): SecurityWebFilterChain {

    //configure security for resource a
    http
            .addFilterAt(authFilterResourceA, SecurityWebFiltersOrder.AUTHENTICATION)
            .authorizeExchange()
            .pathMatchers("/resourceA/**")
            .hasRole(ADMIN_RESOURCE_A)

    //configure security for resource b
    http
            .addFilterAt(authFilterResourceB, SecurityWebFiltersOrder.AUTHENTICATION)
            .authorizeExchange()
            .pathMatchers("/resourceB/**")
            .hasRole(ADMIN_RESOURCE_B)

    // global config
    http
            .httpBasic()
            .disable()
            .formLogin()
            .disable()
            .csrf()
            .disable()
            .cors()
            .disable()
            .authorizeExchange()
            .anyExchange()
            .authenticated()

    return http.build()
}

@Bean("authFilterResourceA")
fun authFilterResourceA(authManager: ReactiveAuthenticationManager): AuthenticationWebFilter {

    val filter = AuthenticationWebFilter(authManager)

    filter.setServerAuthenticationConverter {

        // simplified dummy token conversion for keeping the example as simple as possible

        Mono.justOrEmpty(it)
                .map { it.request.headers.getFirst("X-Application-Authentication") ?: "" }
                .filter { it == "Bearer tokenForA" }
                .map {
                    val authentication = UsernamePasswordAuthenticationToken(
                            "userWithAccessRightsToA",
                            it,
                            listOf(SimpleGrantedAuthority("ROLE_$ADMIN_RESOURCE_A"))
                    )
                    logger.info { "Created authentication: $authentication" }

                    authentication as Authentication
                }
    }

    return filter
}

@Bean("authFilterResourceB")
fun authFilterResourceB(authManager: ReactiveAuthenticationManager): AuthenticationWebFilter {

    val filter = AuthenticationWebFilter(authManager)

    filter.setServerAuthenticationConverter {

        // simplified dummy token conversion for keeping the example as simple as possible

        Mono.justOrEmpty(it)
                .map { it.request.headers.getFirst("X-Application-Authentication") ?: "" }
                .filter { it == "Bearer tokenForB" }
                .map {
                    val authentication = UsernamePasswordAuthenticationToken(
                            "userWithAccessRightsToB",
                            it,
                            listOf(SimpleGrantedAuthority("ROLE_$ADMIN_RESOURCE_B"))
                    )
                    logger.info { "Created authentication: $authentication" }

                    authentication as Authentication
                }
    }

    return filter
}

资料来源:https://github.com/jimonthebarn/spring-webflux-multiple-auth-mechanisms/blob/master/src/main/kotlin/localhost/playground/multi/auth/securityconfig.kt

相关问题