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

登录API端点无法访问:CORS跨域请求拦截问题求助

问题描述

前端从http://localhost:3000发起登录请求到http://localhost:8082/login时触发CORS错误,API无响应。控制台报错:

Access to XMLHttpRequest at 'http://localhost:8082/login' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
AuthenticationService.js:10 AxiosError {message: 'Network Error', name: 'AxiosError', code: 'ERR_NETWORK', config: {…}, request: XMLHttpRequest, …}

后端登录端点代码如下:

@Controller
@CrossOrigin(
    origins = "http://localhost:3000",
    allowCredentials = "true"
)
@RequestMapping("/login")
public class AuthenticationController {

@Autowired
AuthenticationManager authenticationManager;

private static final Logger logger = LoggerFactory.getLogger(AuthenticationController.class);

@PostMapping
public ResponseEntity<?> login(
        @RequestBody Login login,
        HttpServletRequest request,
        HttpServletResponse response
){
    logger.debug("Received login request for username: {}", login.getUsername());
    System.out.println("AuthenticationCOntroller");
    SecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository();
    UsernamePasswordAuthenticationToken token =
            new UsernamePasswordAuthenticationToken(login.getUsername(), login.getPassword());
    Authentication authentication = authenticationManager.authenticate(token);

    if(authentication.isAuthenticated()){
        User user = (User) authentication.getPrincipal();
        Cookie cookie = CookieUtil.generateCookie(user);
        response.addCookie(cookie);
        return ResponseEntity.ok(authentication.getPrincipal());
    }
}

已尝试重构全部代码,但登录功能仍报错。

核心原因分析

  1. Spring Security拦截OPTIONS预检请求:若项目集成了Spring Security,默认会拦截OPTIONS类型的预检请求,导致@CrossOrigin注解的CORS配置无法生效,预检请求得不到正确响应头。
  2. Controller方法分支无返回值:当前login方法仅在认证通过时返回响应,若认证失败或抛出异常,无任何返回结果,会导致请求异常且无法添加CORS头。
  3. CORS配置优先级冲突:@CrossOrigin是局部配置,若存在Spring Security全局CORS配置,局部配置会被覆盖,若全局配置缺失则CORS规则不生效。

解决方案

1. 配置Spring Security放行OPTIONS并启用全局CORS

在Spring Security配置类中添加CORS全局配置,确保预检请求被正确处理:

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.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import java.util.List;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                .csrf(csrf -> csrf.disable()) // 前端未处理CSRF时可暂时禁用
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/login").permitAll()
                        .anyRequest().authenticated()
                );
        return http.build();
    }

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(List.of("http://localhost:3000"));
        config.setAllowedMethods(List.of("GET", "POST", "OPTIONS", "PUT", "DELETE"));
        config.setAllowedHeaders(List.of("*"));
        config.setAllowCredentials(true);
        config.setMaxAge(3600L); // 预检请求缓存时长

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

2. 修复Controller方法的返回值逻辑

确保所有代码分支都有响应返回,避免无响应导致的异常:

@PostMapping
public ResponseEntity<?> login(
        @RequestBody Login login,
        HttpServletRequest request,
        HttpServletResponse response
){
    logger.debug("Received login request for username: {}", login.getUsername());
    System.out.println("AuthenticationCOntroller");
    UsernamePasswordAuthenticationToken token =
            new UsernamePasswordAuthenticationToken(login.getUsername(), login.getPassword());
    
    try {
        Authentication authentication = authenticationManager.authenticate(token);

        if(authentication.isAuthenticated()){
            User user = (User) authentication.getPrincipal();
            Cookie cookie = CookieUtil.generateCookie(user);
            response.addCookie(cookie);
            return ResponseEntity.ok(authentication.getPrincipal());
        }
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
    } catch (AuthenticationException e) {
        logger.error("Authentication failed for username: {}", login.getUsername(), e);
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Authentication failed: " + e.getMessage());
    }
}

3. 移除Controller上的@CrossOrigin注解

使用全局CORS配置后,局部的@CrossOrigin可移除,避免配置冲突。

4. 验证预检请求

用curl发送OPTIONS请求验证响应头:

curl -X OPTIONS http://localhost:8082/login -H "Origin: http://localhost:3000" -i

检查响应头是否包含Access-Control-Allow-Origin: http://localhost:3000和Access-Control-Allow-Credentials: true。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 18:53:23