You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot应用POST请求持续返回403错误排查求助

Spring Boot应用所有POST请求返回403,无效链接未返回404问题

开发Spring Boot应用时遇到以下问题:

  • 发送任意POST请求均返回403响应
  • 即使请求无效链接,返回的仍是403而非404
  • 当前使用Spring Boot 3.1.3版本,曾降级至2.7.15尝试使用WebSecurityConfigurerAdapter旧特性,且已关闭CSRF,但问题仍未解决

相关代码文件

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>register</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>register</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>20</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

SecurityConfig.java

package register;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }

    @Bean
    SecurityFilterChain web(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests((authorize) -> authorize
                        .requestMatchers("/api/**").hasAuthority("ROLE_myAuthority")
                        .anyRequest().authenticated()
                );
        // ...

        return http.build();
    }


    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests((requests) -> requests
                        .requestMatchers("/**").permitAll())
                .build();
    }

/*
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest()
                .permitAll());
        return http.build();
    }

 */
}

EmployeeController.java

package register;


//import com.example.RegisterLogin.Dto.EmployeeDTO;
//import com.example.RegisterLogin.Dto.LoginDTO;
//import com.example.RegisterLogin.Service.EmployeeService;
//import com.example.RegisterLogin.response.LoginResponse;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

@RestController
// @Secured("ROLE_myAuthority")
@CrossOrigin
@RequestMapping("/api/v1/employee")
public class EmployeeController {

    private EmployeeService employeeService;

    @PostMapping(path = "/save")
    public String saveEmployee(@RequestBody EmployeeDTO employeeDTO)
    {
        return employeeService.addEmployee(employeeDTO);
    }
}

application.properties

spring.application.name=register
server.port=8080

spring.jpa.hibernate.ddl-auto=create
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver


spring.datasource.url=jdbc:mysql://localhost:3306/dbkms?createDatabaseIfNotExist=true
spring.datasource.username=username
spring.datasource.password=password

#jpa vendor adapter configuration

spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true

问题根源与修复方案

核心问题

SecurityConfig中定义了两个SecurityFilterChain Bean:

  1. 第一个名为web的Bean,要求/api/**路径必须拥有ROLE_myAuthority权限,其余所有请求都需要认证
  2. 第二个名为securityFilterChain的Bean,意图允许所有请求并关闭CSRF

Spring Security会按Bean的注册顺序匹配过滤器链,第一个web的过滤器链优先级更高,导致所有请求都被它拦截:

  • 未认证的请求直接返回403
  • 无效链接还没到Spring MVC的请求映射阶段就被Security拦截,因此不会返回404

修复步骤

删除多余的web()方法定义,只保留正确的securityFilterChain Bean,修改后的SecurityConfig.java如下:

package register;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder(){
        return  new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        return http.csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests((requests) -> requests
                        .requestMatchers("/**").permitAll())
                .build();
    }
}

额外说明

如果需要对特定路径做权限控制,可在同一个SecurityFilterChain中配置,例如:

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    return http.csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests((requests) -> requests
                    .requestMatchers("/api/v1/employee/save").permitAll() // 允许该路径无需认证
                    .requestMatchers("/api/admin/**").hasAuthority("ROLE_ADMIN") // admin路径需要权限
                    .anyRequest().authenticated()) // 其余路径需要认证
            .build();
}

内容的提问来源于stack exchange,提问作者Ilya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 00:12:07