【问题标题】:Force ServerAuthenticationFailureHandler for a given path in Spring Security 5 (Webflux)在 Spring Security 5 (Webflux) 中为给定路径强制使用 ServerAuthenticationFailureHandler
【发布时间】:2020-12-03 03:18:10
【问题描述】:

我有两条路径/foo 和/bar。对于/foo,我使用了一个自定义身份验证机制。在/bar 我有Basic 身份验证。

除了一种情况外,此设置工作正常。当我没有在/foo 中传递AUTHORIZATION 标头时,基本身份验证就会启动而不是MyAuthenticationFailureHandler

有没有办法为给定路径设置MyAuthenticationFailureHandler?或者,也许我把 SecurityWebFiltersOrder 搞砸了?

我的完整安全配置:

bean<MyReactiveUserDetailsService>()
bean<MyReactiveAuthenticationManager>()
bean {
    ref<ServerHttpSecurity>()
        .securityMatcher {
            if (it.request.path.value().contains("/bar")) {
                ServerWebExchangeMatcher.MatchResult.match()
            } else {
                ServerWebExchangeMatcher.MatchResult.notMatch()
            }
        }
        .formLogin().disable()
        .csrf().disable()
        .logout().disable()
        .httpBasic()
        .and()
        .authorizeExchange()
        .pathMatchers("/bar/**")
        .hasRole("ADMIN")
        .anyExchange().permitAll()
        .and()
        .build()
}

bean {
    ref<ServerHttpSecurity>()
        .securityMatcher {
            if (it.request.path.value().contains("/bar")) {
                ServerWebExchangeMatcher.MatchResult.notMatch()
            } else {
                ServerWebExchangeMatcher.MatchResult.match()
            }
        }
        .httpBasic().disable()
        .formLogin().disable()
        .csrf().disable()
        .logout().disable()
        .authorizeExchange()
        .pathMatchers(
            HttpMethod.POST,
            "/foo/**"
        ).hasRole(
            "ABRACADABRA"
        )
        .anyExchange().permitAll()
        .and()
        .addFilterAt(
            authenticationWebFilter(ref(), ref()),
            SecurityWebFiltersOrder.AUTHENTICATION
        )
        .build()
}
}

private fun authenticationWebFilter(
    reactiveAuthenticationManager: ReactiveAuthenticationManager,
    objectMapper: ObjectMapper
) =
    AuthenticationWebFilter(reactiveAuthenticationManager).apply {
        setServerAuthenticationConverter(MyAuthenticationConverter())
        setRequiresAuthenticationMatcher(
            ServerWebExchangeMatchers.pathMatchers(
                HttpMethod.POST,
               "/foo/**"
            )
        )
        setAuthenticationFailureHandler(MyAuthenticationFailureHandler(objectMapper))
    }

class MyAuthenticationConverter : ServerAuthenticationConverter {
    override fun convert(exchange: ServerWebExchange): Mono<Authentication> {
        val authHeader: String? = exchange.request.headers.getFirst(HttpHeaders.AUTHORIZATION)
        // ... 
        return when {
            isValid(authHeader, ...) -> {
                Mono.just(
                    UsernamePasswordAuthenticationToken(principal, credentials)
                )
            }
            else -> Mono.empty()
        }
    }
}

class MyAuthenticationFailureHandler(private val objectMapper: ObjectMapper) : ServerAuthenticationFailureHandler {
    override fun onAuthenticationFailure(
        webFilterExchange: WebFilterExchange,
        exception: AuthenticationException?
    ): Mono<Void> {
        val response = webFilterExchange.exchange.response
        response.apply {
            statusCode = HttpStatus.OK
            headers.contentType = MediaType.APPLICATION_JSON
            headers.set(HttpHeaders.WARNING, """199 warning "Invalid token"""")
        }

        return response.writeWith(
            Flux.just(
                DefaultDataBufferFactory().wrap(
                    objectMapper.writeValueAsBytes(
                        MyDto(
                            // ...
                        ).toSettingResponse()
                    )
                )
            )
        )
    }
}

【问题讨论】:

    标签: spring-boot kotlin spring-security spring-webflux


    【解决方案1】:

    您可以使用AuthenticationWebFilter 设置自定义ServerAuthenticationFailureHandler。

    @Bean
    public SecurityWebFilterChain securitygWebFilterChain(ServerHttpSecurity http) {
                AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(authenticationManager);
                authenticationWebFilter.setAuthenticationFailureHandler(myAuthenticationFailureHandler) 
         return http.authorizeExchange()
                        .pathMatchers("/user/signup")
                        .permitAll().pathMatchers("/user/login")
                        .permitAll()
                        .anyExchange().authenticated()
                        .and()
                        .securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
                        .addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION)
                        .httpBasic().disable()
                        .csrf().disable()
                        .formLogin().disable()
                        .logout().disable()
                        .build();
            }
    

    【讨论】:

      猜你喜欢
      • 2019-06-21
      • 2019-02-25
      • 2018-03-26
      • 2019-12-10
      • 1970-01-01
      • 2020-04-02
      • 2018-11-03
      • 2018-04-09
      • 1970-01-01
      相关资源
      最近更新 更多