Spring Security配置anyRequest.permitAll仍出现403拒绝访问问题
问题:Spring Security配置允许所有请求仍返回403?
问题描述
我正在开发Spring Boot项目,使用如下Web安全配置:
@EnableWebSecurity public class ApiSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity httpSecurity) throws Exception { // 禁用CSRF httpSecurity.csrf().disable(); // 添加CORS过滤器 httpSecurity.cors(); // 配置匿名/允许访问的路径(即无需认证即可访问的路径) httpSecurity.authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .antMatchers(HttpMethod.GET, "/actuator/health").permitAll(); // 限制所有其他路径为需认证状态(TODO后续改为authenticated()) httpSecurity.authorizeRequests().anyRequest().permitAll(); } }
启动应用后,我能正常访问actuator健康检查URL(http://localhost:9200/actuator/health),但向任意URL发送HTTP POST请求时,会收到403 Access Denied异常。
我原本以为httpSecurity.authorizeRequests().anyRequest().permitAll();会允许所有请求,包括向http://localhost:9200/api/users发送POST请求,但实际仍返回403。需要找出原因。
说明:当前开发阶段希望Spring Security后台运行,但不强制验证任何URL,需允许所有请求,后续几周再调整规则。
更新内容
我已禁用CSRF(如上配置),并将Spring Security日志级别设为DEBUG(以下是application.yml片段):
spring: logging: level: org: springframework: security: DEBUG
测试的curl命令
curl -ik -H "Accept: application/json" -H "Content-Type: application/json" -d '{"name":"ACME, Inc.","website":"http://example.com"}' -X POST 'http://127.0.0.1:9200/ap1/v1/users/' HTTP/1.1 400 Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-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-Length: 0 Date: Mon, 06 Mar 2023 13:26:32 GMT Connection: close
Spring Security日志内容
************************************************************ Request received for POST '/ap1/v1/users/': org.apache.catalina.connector.RequestFacade@14836146 servletPath:/ap1/v1/users/ pathInfo:null headers: host: 127.0.0.1:9200 user-agent: curl/7.64.1 accept: application/json content-type: application/json content-length: 223 Security filter chain: [ WebAsyncManagerIntegrationFilter SecurityContextPersistenceFilter HeaderWriterFilter CorsFilter CsrfFilter LogoutFilter RequestCacheAwareFilter SecurityContextHolderAwareRequestFilter AnonymousAuthenticationFilter SessionManagementFilter ExceptionTranslationFilter FilterSecurityInterceptor ] ************************************************************ 2023-03-06 01:29:15.150 INFO 28967 --- [nio-9200-exec-1] Spring Security Debugger : ************************************************************ New HTTP session created: AAB00E991E9392DCC8799310F1CE82E6 Call stack: at org.springframework.security.web.debug.Logger.info(Logger.java:46) at org.springframework.security.web.debug.DebugFilter$DebugRequestWrapper.getSession(DebugFilter.java:167) at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:229) at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:229) at org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.saveToken(HttpSessionCsrfTokenRepository.java:58) at org.springframework.security.web.csrf.LazyCsrfTokenRepository$SaveOnAccessCsrfToken.saveTokenIfNecessary(LazyCsrfTokenRepository.java:168) at org.springframework.security.web.csrf.LazyCsrfTokenRepository$SaveOnAccessCsrfToken.getToken(LazyCsrfTokenRepository.java:125) at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:124) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:91) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:90) at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:75) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:110) at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:55) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:336) at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:211) at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:183) at org.springframework.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:90) at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:78) at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:67) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:354) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:267) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1732) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:836) ************************************************************ 2023-03-06 01:29:15.157 INFO 28967 --- [nio-9200-exec-1] Spring Security Debugger : ************************************************************ Request received for POST '/error': org.apache.catalina.core.ApplicationHttpRequest@1ae30ce servletPath:/error pathInfo:null headers: host: 127.0.0.1:9200 user-agent: curl/7.64.1 accept: application/json content-type: application/json content-length: 223 Security filter chain: [ WebAsyncManagerIntegrationFilter SecurityContextPersistenceFilter HeaderWriterFilter CorsFilter CsrfFilter LogoutFilter RequestCacheAwareFilter SecurityContextHolderAwareRequestFilter AnonymousAuthenticationFilter SessionManagementFilter ExceptionTranslationFilter FilterSecurityInterceptor ] ************************************************************
问题排查与解决
1. 核心问题:CSRF过滤器未被正确禁用
从日志的过滤器链可以看到,CsrfFilter依然在执行,尽管代码中调用了csrf().disable()。这是因为配置顺序错误,Spring Security的链式调用需要连贯执行,拆分调用会导致默认配置被重新应用。
2. 配置顺序修正
将所有HttpSecurity配置整合为一个链式调用,确保CSRF禁用指令被正确生效:
@EnableWebSecurity public class ApiSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity // 先禁用CSRF .csrf().disable() // 配置CORS .cors() .and() // 统一配置授权规则 .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() .antMatchers(HttpMethod.GET, "/actuator/health").permitAll() // 允许所有其他请求 .anyRequest().permitAll(); } // 添加默认CORS配置(如果没有自定义CORS处理器) @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(Arrays.asList("*")); config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); config.setAllowedHeaders(Arrays.asList("*")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return source; } }
3. 额外注意点
- 日志显示请求返回400而非403,检查到curl请求地址拼写错误:
/ap1/v1/users/应为/api/v1/users/,错误路径会被转发到/error接口,导致异常。 - 确保CORS配置正确,否则OPTIONS预检请求或跨域POST请求仍可能被拦截。
内容的提问来源于stack exchange,提问作者hotmeatballsoup
相关产品推荐
相关产品推荐

