Sa-Token跨域解决方案与CORS问题实战解析

📅 2026/7/18 1:40:52 👁️ 阅读次数 📝 编程学习
Sa-Token跨域解决方案与CORS问题实战解析

1. Sa-Token与CORS跨域问题解析

在前后端分离架构中,跨域问题就像两个说着不同方言的邻居——虽然都在同一个社区(网络环境),但缺乏共同语言(协议规范)就无法正常交流。Sa-Token作为Java生态的轻量级权限认证框架,其默认配置与浏览器同源策略(Same-Origin Policy)的碰撞,常常导致前端控制台出现经典的"CORS policy blocked"错误。

最近在重构一个微服务项目时,就遇到了这样的场景:前端Vue应用调用后端SpringBoot接口时,虽然服务端已经配置了常规的Spring CORS策略,但携带Sa-Token的请求依然被浏览器拦截。经过排查发现,当请求头包含Authorization字段时,浏览器会先发送OPTIONS预检请求(Preflight Request),而Sa-Token默认未处理这类特殊请求。

2. 三种CORS解决方案深度对比

2.1 方案一:SpringBoot原生CORS配置(基础版)

在Spring Security配置类中添加以下代码,这是最基础的跨域解决方案:

@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }

注意:当Sa-Token与Spring Security共存时,必须确保Spring Security配置中允许OPTIONS请求通过:

http.cors().and().authorizeRequests() .requestMatchers(HttpMethod.OPTIONS).permitAll()

实测问题:在Sa-Token 1.34.0版本中,即使这样配置,前端仍可能收到"Invalid CORS request"错误。这是因为Sa-Token的拦截器优先级高于Spring的CORS处理。

2.2 方案二:Sa-Token专属CORS过滤器(推荐方案)

创建自定义CORS过滤器解决优先级问题:

@Component public class SaTokenCorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with, sa-token, Content-Type, Authorization"); if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(req, res); } } }

关键点说明

  1. 必须包含sa-token在允许的Headers中
  2. OPTIONS请求直接返回200状态码
  3. 通过@Component注解自动注册过滤器

2.3 方案三:Nginx层统一处理(生产环境优选)

对于分布式部署环境,在Nginx配置中添加以下规则:

server { listen 80; server_name api.yourdomain.com; location / { add_header 'Access-Control-Allow-Origin' '$http_origin'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since, Cache-Control,Content-Type,Range,Authorization,sa-token'; add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range'; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain; charset=utf-8'; add_header 'Content-Length' 0; return 204; } } }

性能对比

方案适用场景性能影响维护成本
Spring CORS简单单体应用
Sa-Token过滤器Sa-Token项目
Nginx配置微服务架构最小

3. 疑难问题排查手册

3.1 预检请求失败分析

当浏览器控制台出现:

Access to XMLHttpRequest at 'http://api.example.com/login' from origin 'http://front.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check

排查步骤

  1. 使用Chrome开发者工具 → Network标签
  2. 查看OPTIONS请求的Response Headers
  3. 确认包含以下关键头信息:
    • Access-Control-Allow-Origin
    • Access-Control-Allow-Methods
    • Access-Control-Allow-Headers

3.2 Sa-Token特殊配置

application.yml中需要额外配置:

sa-token: # 允许的认证头名称 token-name: satoken # 是否允许从URL参数读取token is-read-header: true is-read-cookie: false is-read-body: false

3.3 多环境配置策略

建议根据不同环境采用不同方案:

  • 开发环境:方案二(快速调试)
  • 测试环境:方案一+方案二组合
  • 生产环境:方案三(Nginx统一管理)

4. 进阶:Sa-Token SSO中的CORS处理

在单点登录场景下,跨域问题会更加复杂。需要在Sa-Token配置中添加:

@Configuration public class SaTokenSsoConfig { @Autowired private void configSso(SaTokenConfig cfg) { cfg.sso // 配置SSO相关域名白名单 .setAllowOrigin("*") // 开放所有OPTIONS请求 .setNotInterceptUri("/**"); } }

同时前端axios实例需要特殊处理:

const service = axios.create({ baseURL: process.env.VUE_APP_BASE_API, withCredentials: true, // 携带cookie timeout: 5000, headers: { 'Content-Type': 'application/json' } }) // 请求拦截器 service.interceptors.request.use(config => { if (store.getters.token) { config.headers['sa-token'] = getToken() } return config }, error => { return Promise.reject(error) })

5. 性能优化建议

  1. 缓存控制:对于方案二,设置合理的Max-Age值(建议3600秒)
  2. 精确域名:生产环境避免使用*,改为具体域名白名单
  3. Header精简:只暴露必要的Headers,减少网络开销
  4. 链路监控:使用APM工具监控OPTIONS请求耗时

我在实际项目中发现,当QPS超过500时,不合理的CORS配置会导致额外15%-20%的性能损耗。经过Nginx层优化后,性能回归正常水平。