为什么Spring ResponseStatusException 400被翻译成403

Kev*_*vin 7 spring spring-mvc spring-security spring-boot

我有一个带有此安全配置的 Spring boot 应用程序:

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .headers().frameOptions().sameOrigin().and()
        .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
        .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
        .authorizeRequests()
            .antMatchers("/api/authenticate/**", "/h2-console/**").permitAll()
            .anyRequest().authenticated();
  }
Run Code Online (Sandbox Code Playgroud)

在我的应用程序代码中,我抛出一个 ResponseStatusException:

    if (existingTenant.isPresent()) {
      throw new ResponseStatusException(
          HttpStatusCode.valueOf(400),
          "Tenant with name " + tenant.name() + " already exists");
    }
Run Code Online (Sandbox Code Playgroud)

但我得到的 api 响应是 403:

* Mark bundle as not supporting multiuse
< HTTP/1.1 403 
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: SAMEORIGIN
< Content-Length: 0
< Date: Sat, 13 Aug 2022 19:26:27 GMT
< 
* Connection #0 to host localhost left intact
Run Code Online (Sandbox Code Playgroud)

我看到的唯一日志记录是:

2022-08-13T12:32:09.260-07:00 WARN 79360 --- [nio-8080-exec-6] .wsmaResponseStatusExceptionResolver:已解决[org.springframework.web.server.ResponseStatusException:400 BAD_REQUEST“名为tenant1的租户已经存在”]

为什么响应没有获得400我在异常中设置的响应代码?

Kev*_*vin 6

问题是 Spring Boot 启用了 ErrorMvcAutoConfiguration。我看到的 403 错误是因为抛出异常时的默认行为是以用户/error身份提供页面anonymous。在我看来,这与新用户如何配置其网络安全性的交互效果很差。我能够通过更改安全配置以允许匿名访问该/error页面来解决该问题。

AffirmativeBased#decide我只能通过添加断点并检查请求来找出问题所在。我注意到该请求是针对/error原始网址而不是原始网址,因此我能够对发生的情况做出一些有根据的猜测。

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .headers().frameOptions().sameOrigin().and()
        .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
        .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
        .authorizeRequests()
            .antMatchers("/api/authenticate/**", "/h2-console/**").permitAll()
            // ---------------------------------------------
            .antMatchers("/error").anonymous() // <----- Fix
            .anyRequest().authenticated();
  }
Run Code Online (Sandbox Code Playgroud)

处理此问题的另一种方法是通过在任何位置添加此注释来禁用自动配置@SpringBootApplication

@EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class})
Run Code Online (Sandbox Code Playgroud)


小智 5

对于在 Spring Boot 3 中遇到此问题并且之前的答案不起作用的任何人,我在文档中找到了解决方案:

简而言之,您必须允许DispatcherType.ERROR通过以下方式通过过滤:

http
    .authorizeHttpRequests((authorize) -> authorize
        .dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
    )
Run Code Online (Sandbox Code Playgroud)