Axios跨域请求接口,如何完成cookie级别的鉴权?
发布于 作者:苏南大叔 来源:程序如此灵动~
为啥说cookie级别的鉴权?因为鉴权方式很多,cookie级别是传统网站的接口鉴权方式,而现代构架里多使用header+token的方式进行数据传输处理。完成cookie级别的跨域接口鉴权,不是一件容易的事情,要满足的条件很多。在本文中,苏南大叔将要讲述跨域接口cookie鉴权,需要满足的一系列条件。

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。测试环境:win10,chrome@135.0.7049.41,nginx@1.15.11。
动作发起方:axios 主动带 cookie
axios框架规定:ajax类似请求,默认是不携带cookie的。首先要先开启它的设定:withCredentials: true。其次确保请求的header符合服务器CORS策略(一般情况下都符合)。
参考方案:
axios.defaults.withCredentials = true;或者:
const axiosInstance = axios.create({ withCredentials: true });或者:
axios.get('<跨域接口>', {
withCredentials: true,
//...
})参考文章:
动作接收方:cors 允许带 cookie
服务器端需要正确处理CORS请求,特别是OPTIONS预检请求:
- 【重点】设置
Access-Control-Allow-Credentials:true,允许携带Cookie。 - 【重点】设置
Access-Control-Allow-Origin为允许的来源域名(如https://newsn.net),这里可没说设置为*哦。 - 设置
Access-Control-Allow-Methods,允许的HTTP方法(如GET,POST)。 - 设置
Access-Control-Allow-Headers,允许的自定义头部(如Content-Type)。
参考文章:
服务器端颁发正确的cookie
因为是跨越的接口请求,所以要求:
- 设置
cookie的SameSite属性为None,它要求secure属性。 - 设置
cookie的Secure属性为True,它要求https协议。 - 服务器端需使用
https协议,它要求服务器部署证书。
参考文章:
客户端完整代码

客户端代码:
<script src="https://fastly.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<button id="getRequest">Send GET Request</button>
<button id="postRequest">Send POST Request</button>
<div id="response"></div>
<script>
const axiosInstance = axios.create({
withCredentials: true, // 允许携带跨域Cookie
});
// 发送GET请求
document.getElementById('getRequest').addEventListener('click', () => {
axiosInstance.get('https://v/get.php?a=sunan')
.then(response => {
document.getElementById('response').innerText = JSON.stringify(response.data);
})
.catch(error => {
document.getElementById('response').innerText = error;
});
});
// 发送POST请求
document.getElementById('postRequest').addEventListener('click', () => {
axiosInstance.post('https://v/post.php', { a: 'sunan'},
{headers: { 'Content-Type': 'application/x-www-form-urlencoded' }})
.then(response => {
document.getElementById('response').innerText = JSON.stringify(response.data);
})
.catch(error => {
document.getElementById('response').innerText = 'POST Error: ' + error;
});
});
</script>参考文章:
nginx配置
仅供参考:
server {
listen 80;
server_name v;
root "E:/v";
location / {
include E:/v/nginx.htaccess;
autoindex off;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
# 动态跨域处理
set $cors_origin '';
if ($http_origin ~* (http://h|http://newsn.net|https://newsn.net)) {
set $cors_origin $http_origin;
}
# 添加跨域响应头
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,access-control-allow-origin, authority, content-type, version-info, X-Requested-With' always;
# 处理 OPTIONS 请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $cors_origin always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,access-control-allow-origin, authority, content-type, version-info, X-Requested-With' always;
add_header 'Access-Control-Max-Age' 1728000 always;
add_header 'Content-Length' 0;
return 204;
}
}
}服务端完整代码
最主要的就是使用https协议,然后设置默认cookie的samesite和secure。参考文章:
定制服务器端的cookie
需要对服务器端的session进行定制,主要就是secure和samesite:session_start.php:
function is_https() {
return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ||
(!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https');
}
session_name('MyCustomSession');
session_set_cookie_params([
'lifetime' => 3600, // 1 小时
'path' => '/',
'domain' => $_SERVER['HTTP_HOST'], // 动态设置域名
'secure' => is_https(), // 根据是否 HTTPS 设置 secure 属性
'httponly' => true, // 防止 JavaScript 访问
'samesite' => 'None' // 设置 SameSite 属性
]);
session_start();其它代码
login.php:
require_once 'session_start.php';
$_SESSION["login"] = "ok";check.php:
require_once 'session_start.php';
if(@$_SESSION["login"] != "ok"){
echo "请先登录!";
exit;
}get.php:
require_once 'check.php';
$aa = @$_GET["a"];
echo "{'ok':'$aa'}";post.php:
require_once 'check.php';
$aa = @$_POST["a"];
echo "{'ok':'$aa'}";题外话
正常来说,鉴权很少用cookie了,都是在header头里面增加authorization字段,一般的鉴权方式都是Bearer。参考:
总结
1.Axios设置:withCredentials: true。
2.服务器OPTIONS请求: 设置 Access-Control-Allow-Origin、Access-Control-Allow-Credentials等。
3.服务器端Cookie设置: 确保SameSite=None和Secure=true。
4.测试页面:使用 Axios发送跨域请求并携带Cookie。
虽然本文没有提到csrf跨域脚本攻击,但是这就是目前的浏览器环境下,如果想要跨域攻击成功,所需要的基本条件。可见条件相当苛刻,很难达成。除非客户端是很古老版本的浏览器,或者被定制的浏览器。或者特殊版本的electron/nwjs,才有可能攻击成功。总之,突破口在客户端在浏览器本身之上,但是很难达成。
更多苏南大叔的axios相关经验文章,请参考: