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
相关经验文章,请参考:


