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

📅 2026/7/18 1:40:36
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); } } }关键点说明必须包含sa-token在允许的Headers中OPTIONS请求直接返回200状态码通过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; charsetutf-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 doesnt pass access control check排查步骤使用Chrome开发者工具 → Network标签查看OPTIONS请求的Response Headers确认包含以下关键头信息Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers3.2 Sa-Token特殊配置在application.yml中需要额外配置sa-token: # 允许的认证头名称 token-name: satoken # 是否允许从URL参数读取token is-read-header: true is-read-cookie: false is-read-body: false3.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. 性能优化建议缓存控制对于方案二设置合理的Max-Age值建议3600秒精确域名生产环境避免使用*改为具体域名白名单Header精简只暴露必要的Headers减少网络开销链路监控使用APM工具监控OPTIONS请求耗时我在实际项目中发现当QPS超过500时不合理的CORS配置会导致额外15%-20%的性能损耗。经过Nginx层优化后性能回归正常水平。