一、前言
项目出于安全评测的要求,需要页面在浏览器及其标签页关闭的时候登出,保证每次进入系统都重新登录。 核心处理逻辑有如下几点:
- 监听浏览器关闭事件
- 关闭时清除本地存储的token
- 关闭时调用登出接口保证后端redis中token被清除
通过AI和网络搜索 给出的方案,很快就实现了。但在自测验证过程中,发现有两个费劲周折的问题。
- beforeunload 事件在页面刷新时也会触发,而排除是刷新的情况 试了N种方案都不尽人意
- 标签页关闭后axios触发的登出请求 会被浏览器取消,后端接收不到。
折腾一波后,最终都解决了,这里记录下解决方案。
二、解决方案
2.1 标签页关闭时登出,但排除刷新的场景
在unload事件中增加刷新情况的判断。除了下面代码中时间差的判断方法外,还尝试过performance.navigation等方案,都无效。
javascript
let _beforeUnload_time = 0
let _gap_time = 0
window.onbeforeunload = () => {
_beforeUnload_time = new Date().getTime();
console.log("beforeUnload_time", _beforeUnload_time);
};
window.onunload = (event) => {
_gap_time = new Date().getTime() - _beforeUnload_time;
console.log("gap_time", _gap_time);
if (_gap_time <= 5 || event.altKey) {
// 执行关闭需要进行的操作,1. 清除本地缓存;2. 发送登出接口
console.log("xxxxxxx关闭");
}else{
console.log("页面刷新");
}
};
2.2 登出请求,避免被浏览器取消
Fetch的keepalive可以在页面卸载(如用户关闭标签页或跳转到新页面)后,确保请求仍能在后台完成的选项
php
fetch('/api/logout', {
method: 'GET',
headers: {
'Authorization': token
},
keepalive: true, // 类似 sendBeacon 的行为
});
2.3 浏览器关闭再进入的场景
基于sessionStorage做判断,存储在 sessionStorage 里面的数据在页面会话结束时会被浏览器自动清除。
arduino
// 初次进入跳转登录页面
if (!sessionStorage.getItem("entered")) {
location.hash = "#/login";
sessionStorage.setItem("entered", "true");
}