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

Spring Security+OAuth2 REST API预检请求跨域校验失败问题排查

解决Spring Security OAuth2 4.x版本AJAX跨域CORS问题

兄弟,我之前在使用Spring Security OAuth2 2.0.x版本的时候也踩过这个CORS的坑——明明配置了Spring MVC的CORS,但AJAX调用/oauth/token或者带token的API还是报跨域错误。问题出在OAuth2的核心端点(比如/oauth/token)并不受普通Spring MVC的CORS规则管控,而且请求会先经过Spring Security的过滤器链,普通CORS过滤器如果顺序不对,根本没机会添加响应头。

下面给你针对这个版本的具体解决方案:

1. 自定义CORS过滤器并调整执行顺序

首先要写一个全局的CORS过滤器,并且让它在Spring Security的过滤器之前执行,这样预检请求(OPTIONS)和实际请求都能先拿到CORS响应头。

import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CorsFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.setHeader("Access-Control-Allow-Origin", "*"); // 生产环境建议指定具体域名
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type, Accept, X-Requested-With, remember-me");
        
        // 处理预检OPTIONS请求,直接返回200
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            filterChain.doFilter(request, response);
        }
    }
}

然后在Spring配置里注册这个过滤器,并且设置优先级高于Spring Security:

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;

@Configuration
public class CorsConfig {

    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        FilterRegistrationBean<CorsFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new CorsFilter());
        registrationBean.addUrlPatterns("/*"); // 对所有URL生效
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 优先级最高,在Security过滤器之前执行
        return registrationBean;
    }
}

2. 调整Spring Security配置,允许CORS和OPTIONS请求

在你的WebSecurityConfigurerAdapter配置里,要明确允许OPTIONS请求通过,并且开启CORS支持:

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.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.header.writers.StaticHeadersWriter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable() // 如果是纯API服务,可关闭CSRF
            .authorizeRequests()
                .antMatchers("/oauth/token", "/oauth/authorize").permitAll() // 放开OAuth2端点
                .anyRequest().authenticated()
            .and()
            .cors() // 开启Spring Security的CORS支持
            .and()
            .headers()
                .addHeaderWriter(new StaticHeadersWriter("Access-Control-Allow-Origin", "*")); // 双重保障,也可以在这里加
    }
}

3. 配置AuthorizationServer允许OPTIONS请求

在你的AuthorizationServerConfigurerAdapter里,要确保/oauth/token端点接受OPTIONS请求,因为预检请求会先发送OPTIONS到这个端点:

import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
            .tokenKeyAccess("permitAll()")
            .checkTokenAccess("isAuthenticated()")
            .allowFormAuthenticationForClients();
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        // 这里配置你的客户端信息,比如clientId、secret、授权类型等
        clients.inMemory()
            .withClient("your-client-id")
            .secret("your-client-secret")
            .authorizedGrantTypes("password", "refresh_token")
            .scopes("read", "write");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 确保端点支持OPTIONS请求
        endpoints.getFrameworkEndpointHandlerMapping().setAllowOptions(true);
    }
}

最后检查点

  • 确保你的AJAX请求里没有带自定义的未被允许的请求头,如果有,要在CorsFilter的Access-Control-Allow-Headers里加上。
  • 生产环境不要用*作为Access-Control-Allow-Origin,要指定具体的前端域名,比如http://localhost:3000。
  • 清除浏览器缓存,有时候旧的CORS缓存会导致问题。

按照上面的配置调整后,AJAX请求应该就能正常获取token并调用API了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:09:14