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

Maven运行Spring Boot项目时POST请求出现401未授权错误求助

问题描述
  • 技术栈:Java 21 + Spring Boot 3.2.4,IntelliJ IDEA开发
  • 本地IDE启动(运行按钮/Control+R):端口3000的React前端可正常向http://localhost:8080/api/v1/register发送POST请求,用户数据成功存入本地3306端口的MySQL数据库
  • Maven命令启动(执行mvn clean package后用mvn spring-boot:run):相同的POST请求返回401(Unauthorized)错误
  • 需求:解决该权限拦截问题,同时方案需适配Docker部署的MySQL

相关代码

WebConfig.java

package com.cinema.backend.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Arrays;

@Configuration
public class WebConfig {

    private static final long MAX_AGE = 3600L;

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:3000");
        config.setAllowedHeaders(Arrays.asList(
                "Authorization",
                "Cache-Control",
                "Content-Type"));
        config.setAllowedMethods(Arrays.asList(
                HttpMethod.GET.name(),
                HttpMethod.POST.name(),
                HttpMethod.PUT.name(),
                HttpMethod.DELETE.name(),
                HttpMethod.OPTIONS.name()));
        config.setMaxAge(MAX_AGE);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);

        return new CorsFilter(source);
    }

}

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.2.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.cinema</groupId>
    <artifactId>backend</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>backend</name>
    <description>Backend Application for Cinema</description>
    <properties>
        <java.version>21</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>
    </dependencies>

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

</project>

UserController.java

package com.cinema.backend.controller;

import com.cinema.backend.models.User;
import com.cinema.backend.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @PostMapping("/api/v1/register")
    User newUser(@RequestBody User newUser){
        return userRepository.save(newUser);
    }

}

解决方案

1. 添加Spring Security配置类

创建SecurityConfig.java,明确放行注册接口的匿名访问权限,同时适配CORS规则:

package com.cinema.backend.config;

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.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.cors.CorsConfiguration;

import java.util.Arrays;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final WebConfig webConfig;

    public SecurityConfig(WebConfig webConfig) {
        this.webConfig = webConfig;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // 关闭CSRF防护:跨域POST请求默认会被CSRF拦截,注册接口无需CSRF验证
                .csrf(csrf -> csrf.disable())
                // 配置CORS规则
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                // 接口权限控制
                .authorizeHttpRequests(auth -> auth
                        // 允许匿名访问注册接口
                        .requestMatchers("/api/v1/register").permitAll()
                        // 其他所有接口需要认证
                        .anyRequest().authenticated()
                );

        // 将自定义CorsFilter置于Security认证过滤器之前,确保CORS规则优先生效
        http.addFilterBefore(webConfig.corsFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://localhost:3000");
        config.setAllowedHeaders(Arrays.asList(
                "Authorization",
                "Cache-Control",
                "Content-Type"));
        config.setAllowedMethods(Arrays.asList(
                "GET", "POST", "PUT", "DELETE", "OPTIONS"));
        config.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}

2. 适配Docker部署的MySQL

修改src/main/resources/application.properties,根据Docker环境调整数据库连接配置:

# 数据库连接配置
# 本地MySQL使用localhost;Docker容器中若用自定义网络,替换为MySQL容器名(如mysql-container)
spring.datasource.url=jdbc:mysql://localhost:3306/你的数据库名?useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true
spring.datasource.username=你的数据库用户名
spring.datasource.password=你的数据库密码
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# JPA配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect

3. 验证Maven启动配置

  • 确认application.properties位于src/main/resources目录,Maven打包时会自动将其加入target/classes
  • 执行mvn clean package后,检查target/classes下是否存在该配置文件
  • 启动时可添加日志参数排查配置加载:mvn spring-boot:run -Dlogging.level.org.springframework=DEBUG

问题根源

IDE启动时默认加载开发环境配置(如application-dev.properties),可能已临时放开权限或关闭Security;而Maven命令启动默认加载application.properties,Spring Security默认对所有接口启用认证,导致注册接口被拦截返回401。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:23:10