使用 Sa-Token CORS 策略处理跨域问题(三种方式全版)

前言

之前写了一篇 使用 Sa-Token 的全局过滤器解决跨域问题(三种方式全版) 详解了如何使用 Sa-Token 的全局过滤器解决各种跨域问题,正好最近 Sa-Token 更新了版本,最新版本简化了跨域处理方案, 本文章将介绍一下最新版本的写法,以便给正在使用新版本的同学做个参考。

注:本文章仅针对新版本(v1.42.0 及以上版本)提供参考,低于 v1.42.0 版本可以移步上述文章进行了解。


在 web 开发中,跨域绝对是比较折磨新同学的一个问题,本文将讲解三种常见的跨域情形,并讲解如何使用 Sa-Token 框架解决跨域问题。

什么情况下会发生跨域

简单理解,就是你在 A 域名下的页面,去调用 B 域名的接口,浏览器感觉你这次调用可能是不安全的请求行为,于是它需要用 cors 安全策略来确认一下这个请求是由用户真实的意愿发出的,而不是被 csrf 伪造请求攻击偷偷发送的。(这么说只是为了方便大家理解,不是特别严谨,实际上同域名下部分情形也会出现跨域问题)

请仔细理解上面这段话,因为它说明了两点:

  • 跨域不是后端接口对前端浏览器的限制,而是前端浏览器对用户的限制。
  • 跨域不是在保护后端接口免受攻击,而是浏览器在保护用户,避免用户发送自己不想发送的请求。

请一定要记住上面跨域的本质,明白了症状和原因,我们才能对症下药。

一般情况下,我们会碰到三种跨域场景:

  • 1、本地页面调用测试服务器,只在项目开发阶段会有跨域问题。(比较简单)
  • 2、使用 header 头提交 token,产生的跨域问题。(比较常见+通用,推荐使用)
  • 3、使用第三方 Cookie 提交 token,产生的跨域问题。(最古老的方案,目前新版浏览器对此方案限制越来越严格,非必要不选择此方案,如果对此方案不是很熟悉就贸然使用也容易出现安全问题)

跨域情形一:只在项目开发阶段会有跨域问题

有些公司项目的开发方式为:

  • 在项目开发时:使用本地页面调用测试服务器接口。(域名不同,存在跨域问题)
  • 在项目部署时:将后端接口和前端页面部署在同一域名下。(域名一致,不存在跨域问题)

这种情况下比较好解决,在代码层面我们无需任何更改,只在前端客户端做出一定的更改就行了。比如说:在前端配置一个代理服务器,或者修改一下 Chrome 客户端使其去除跨域限制。

具体的方案有很多,大家可参考这篇博客:手把手教你解决web前端跨域问题

上面是说的普通前后端分离开发,而在APP、小程序 开发中,其天然就是个没有跨域限制的客户端,我们什么都不用做就能解决跨域问题。

跨域情形二:使用 header 头提交 token,产生的跨域问题(比较常见+通用,推荐使用)

当你使用 header 头提交 token 时,会产生跨域问题。此方案比较常见+通用,推荐使用。

jquery 代码示例:

js 复制代码
	$.ajax({
		url: "/user/getInfo",
		type: "post", 
		data: {},
		dataType: 'json',
		headers: {
			"X-Requested-With": "XMLHttpRequest",
			// 重点处:请求的 header 头里塞入自定义参数
			"satoken": localStorage.getItem("satoken")
		},
		success: function(res){
			console.log(res);
		},
		error: function(xhr, type, errorThrown){
			return alert("异常:" + JSON.stringify(xhr));
		}
	});

Axios 代码示例:

js 复制代码
    axios({
        url: "/user/getInfo",
        method: 'post',
        data: {},
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
			// 重点处:请求的 header 头里塞入自定义参数
            "satoken": localStorage.getItem("satoken")
        }
    }).
    then(function (response) { // 成功时执行
        const res = response.data;
		console.log(res);
    }).
    catch(function (error) {
        return alert("异常:" + JSON.stringify(error));
    })

此时在后端,我们应该添加以下响应头:

java 复制代码
/**
 * [Sa-Token 权限认证] 配置类 
 *
 * @author click33
 */
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {

	/**
	 * CORS 跨域处理策略
	 */
	@Bean
	public SaCorsHandleFunction corsHandle() {
		return (req, res, sto) -> {
			res.
				// 允许指定域访问跨域资源
				setHeader("Access-Control-Allow-Origin", "*")
				// 允许所有请求方式
				.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
				// 有效时间
				.setHeader("Access-Control-Max-Age", "3600")
				// 允许的header参数
				.setHeader("Access-Control-Allow-Headers", "*");

			// 如果是预检请求,则立即返回到前端
			SaRouter.match(SaHttpMethod.OPTIONS)
				.free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
				.back();
		};
	}
}

WebFlux 同理,此处理策略全环境通用。

这是最古老的方案,目前新版浏览器对此方案限制越来越严格,非必要不选择此方案,如果对此方案不是很熟悉就贸然使用也容易出现安全问题。

jquery 代码示例:

js 复制代码
	$.ajax({
		url: "/user/getInfo",
		type: "post", 
		data: {},
		dataType: 'json',
		// 重点处:指定是跨域模式,需要提交第三方 Cookie 
		crossDomain: true,
		xhrFields:{
			withCredentials: true
		},
		headers: {
			"X-Requested-With": "XMLHttpRequest"
		},
		success: function(res){
			console.log(res);
		},
		error: function(xhr, type, errorThrown){
			return alert("异常:" + JSON.stringify(xhr));
		}
	});

Axios 代码示例:

js 复制代码
    axios({
        url: "/user/getInfo",
        method: 'post',
        data: {},
		// 重点处:开启第三方 Cookie 
		withCredentials: true,
        headers: {
            "Content-Type": "application/x-www-form-urlencoded"
        }
    }).
    then(function (response) { // 成功时执行
        console.log(res);
    }).
    catch(function (error) {
        return alert("异常:" + JSON.stringify(error));
    })

此时在后端,我们应该添加以下响应头:

java 复制代码
/**
 * [Sa-Token 权限认证] 配置类 
 *
 * @author click33
 */
@Configuration
public class SaTokenConfigure implements WebMvcConfigurer {

	/**
	 * CORS 跨域处理策略
	 */
	@Bean
	public SaCorsHandleFunction corsHandle() {
		return (req, res, sto) -> {
			// 获得客户端domain
			String origin = req.getHeader("Origin");
			if (origin == null) {
				origin = req.getHeader("Referer");
			}

			// ---------- 设置跨域响应头 ----------
			res
				// 允许第三方 Cookie
				.setHeader("Access-Control-Allow-Credentials", "true")
				// 允许指定域访问跨域资源
				.setHeader("Access-Control-Allow-Origin", origin)
				// 允许所有请求方式
				.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE")
				// 允许的header参数
				.setHeader("Access-Control-Allow-Headers", "x-requested-with,satoken")
				// 有效时间
				.setHeader("Access-Control-Max-Age", "3600")
			;

			// 如果是预检请求,则立即返回到前端
			SaRouter.match(SaHttpMethod.OPTIONS)
				.free(r -> System.out.println("--------OPTIONS预检请求,不做处理"))
				.back();
		};
	}

}

WebFlux 同理,此处理策略全环境通用。

注意:根据浏览器最新标准,Cookie 模式认证需要做到以下两点:

1、Cookie 属性指定 secure=true 以及 sameSite=None

yml 复制代码
sa-token:
    is-log: true
    cookie:
        # 指明当前为 https 安全连接
        secure: true
        # 指明第三方 Cookie 限制级别为:不限制
        sameSite: None

2、后端的服务必须是 https 形式,前端无要求。

相关推荐
南雨北斗6 分钟前
8.安装laravel12和编程学习的几点思考
后端
极客先躯17 分钟前
高级java每日一道面试题-2025年3月31日-微服务篇[Nacos篇]-Nacos集群模式下的部署方案有哪些?
java·开发语言·微服务
计算机学姐20 分钟前
基于SSM的校园美食交流系统
java·vue.js·mysql·spring·tomcat·mybatis·美食
惊鸿Randy27 分钟前
AI模型多阶段调用进度追踪系统设计文档
java·spring boot·ai·ai编程
hweiyu0038 分钟前
maven导入本地jar示例
java·maven·jar
佩奇的技术笔记43 分钟前
Java学习手册:Java集合框架详解
java·学习
异常君1 小时前
Java 9 特性详解:从模块系统到 API 增强的全面剖析
java·后端
alien爱吃蛋挞1 小时前
【JavaEE】TCP流套接字编程
java·网络·java-ee
程序猿chen1 小时前
《JVM考古现场(十八):造化玉碟·用字节码重写因果律的九种方法》
java·jvm·git·后端·面试·java-ee·跳槽
南雨北斗1 小时前
7.安装Laravel 12 PHP需要开启的扩展
后端