SecurityFilterChain .anyRequest().permitAll() 不允许 POST 个请求

SecurityFilterChain .anyRequest().permitAll() doesn't allow POST requests

使用 Spring Boot 2.7 (Spring Security 5.7.1) 并尝试将 API 配置为资源服务器和 OAuth2 客户端我发现了一个我不明白的行为了解:

@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        .mvcMatchers("/swagger-ui/**", "/api-docs/**").permitAll()
                        .anyRequest().permitAll())

                // register OAuth2 resource server
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)

                // register OAuth2 client
                .oauth2Client(withDefaults());

        return http.build();
    }
}

检查日志,所有这些过滤器都适用

o.s.s.web.DefaultSecurityFilterChain     : Will secure any request with 

org.springframework.security.web.session.DisableEncodeUrlFilter@320ca97c,
org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@3c592c0c,
org.springframework.security.web.context.SecurityContextPersistenceFilter@2b33e616,
org.springframework.security.web.header.HeaderWriterFilter@2e9bff08,
org.springframework.security.web.csrf.CsrfFilter@7926d092,
org.springframework.security.web.authentication.logout.LogoutFilter@37227aa7,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter@6f18445b,
org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter@42af2977,
org.springframework.security.web.savedrequest.RequestCacheAwareFilter@79e3f444, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@1252d480,
org.springframework.security.web.authentication.AnonymousAuthenticationFilter@3979c6e8,
org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter@19faa9dc,
org.springframework.security.web.session.SessionManagementFilter@7d3b4646,
org.springframework.security.web.access.ExceptionTranslationFilter@6cb2d5ea,

到目前为止,此配置在我正在保护的其他 API 中按预期工作。但是,在这个特殊的情况下,我看到没有保护任何端点:

我可以访问任何 GET 端点,但任何 POST 端点 returns 和 403 FORBIDDEN。但是,如果我向请求添加一个令牌,我可以访问它们 即使它是一个过期的令牌

仅这一点我无法理解,因为 .anyRequest().permitAll() 如果我没记错的话,应该取消任何保护。

如果我注释掉配置 oauth2 ResourceServer 的行

`// .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)`

此过滤器消失

org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter

并且不能再使用 POST 个端点,即使令牌已过期

从逻辑上讲,我希望 API 是 oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt) 所以

我怎么在使用 .anyRequest().permitAll()) 时无法访问 POST 端点?

免责声明:我知道如果所有端点都必须是 public,那么将 API 声明为资源服务器是没有意义的。 Discord 回调将访问端点,我必须弄清楚我是否可以使用 OAuth

保护它们

编辑:

server.servlet.context-path = /api

控制器

@RestController
@RequestMapping("/slack")
public class SlackBotController {
    @PostMapping("/test")
    public String test(@RequestBody String a) {
        return a;
    }

    @GetMapping("/test")
    public String testGet() {
        return "OK";
    }
}

请求

GET/POST http://localhost:8081/api/slack/test

请求headers

User-Agent: PostmanRuntime/7.29.0
Accept: */*
Postman-Token: f20ba7a6-26e5-47c4-a827-0596afec27b8
Host: localhost:8081
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 3
Cookie: JSESSIONID=D1C2B2668DC130C63DDE03F30574ED5F; JSESSIONID=823D79956CFBF14F3C77C96E29F4131C

回应headers

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: DENY
Content-Type: application/json
Transfer-Encoding: chunked
Date: Fri, 03 Jun 2022 12:03:00 GMT
Keep-Alive: timeout=60
Connection: keep-alive

这里的问题是CSRF保护。当您使用 http.oauth2ResourceServer() Spring 安全配置 CSRF 以忽略包含 header Authorization: Bearer whatever 的请求时,请注意它必须包含 Bearer 前缀。

在您共享的请求示例中,您没有包括授权 header。

在 Spring 安全性中查看 at the code

之所以POST端点或POSTreturns一个403 FORBIDDEN是因为spring中默认启用了CSRF保护。

这意味着每个 修改 请求(POST、PUT、DELETE、PATCH)都需要一个 CSRF 令牌。否则请求将被拒绝以防止 CSRF 攻击。

要禁用 CSRF 保护:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
      .csrf().disable();
}