Spring Security Spring Webflux自定义WebFilter导致所有开放端点的HTTP 200响应

ivqmmu1c  于 2023-08-05  发布在  Spring
关注(0)|答案(1)|浏览(139)

我正在开发一个Sping Boot Webflux应用程序,它有一个自定义的WebFilter,可以根据从请求中派生的Principal对象进行即时用户创建。
WebFilter适用于需要身份验证的端点。但是对于不需要身份验证的端点,任何匹配以下模式的内容都将返回HTTP 200 -即使该端点不存在。此外,似乎没有调用端点。
我的安全配置:

@Bean
    public SecurityWebFilterChain securityWebFilterChain(
            ServerHttpSecurity http) {
        return http.cors(cors -> cors.configurationSource(swx -> corsConfiguration()))
                .csrf(ServerHttpSecurity.CsrfSpec::disable)
                .securityMatcher(new NegatedServerWebExchangeMatcher(
                        ServerWebExchangeMatchers.pathMatchers("/actuator/**")))
                .authorizeExchange((authorize) -> authorize
                        .pathMatchers("/foo/**")
                        .permitAll()
                        .anyExchange()
                        .authenticated()
                )
                .oauth2ResourceServer(ors -> ors.jwt(jwt -> {}))
                .build();
    }

字符串
我的网络过滤器:

@Component
public class JITUserFilter implements WebFilter {

    private static final Logger logger = LoggerFactory.getLogger(JITUserFilter.class);

    private final UserService userService;

    public JITUserFilter(UserService userService) {
        this.userService = userService;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange,
                             WebFilterChain webFilterChain) {
        return serverWebExchange.getPrincipal().flatMap(p -> {
            Optional<String> email = Optional.empty();
            if (p instanceof JwtAuthenticationToken) {
                email = Optional.of(((JwtAuthenticationToken)p).getToken().getClaimAsString("https://my-app.example.com/email"));
            }
            Optional<User> userOpt = userService.findUserByExternalId(p.getName());
            if (userOpt.isEmpty()) {
                logger.info("No existing user found; creating new with externalId {}", p.getName());
                User user = new User();
                user.setExternalId(p.getName());
                user.setEmail(email.orElse(null));
                userService.createUser(user);
            }
            return webFilterChain.filter(serverWebExchange);
        });
    }
}


我在/foo/bar上有一个POST端点,我希望记录一些消息,并在命中时返回一个虚拟响应,但在向该端点发布时,我得到的只是一个200 OK响应。为什么?为什么?

ukdjmx9f

ukdjmx9f1#

事实证明,这里发生的事情是,如果没有传递Authentication头,那么web过滤器中的serverWebExchange.getPrincipal()就是空的Mono。如果是这种情况,整个块将被跳过,这将导致HTTP 200响应。
解决方案是在结尾添加:

.switchIfEmpty(Mono.defer(() -> webFilterChain.filter(serverWebExchange)))

字符串
从而过滤器链的其余部分继续。

相关问题