在前端开发中 , 判断用户登录状态是否过期是一个常见的需求。尤其是在复杂的场景中 , 准确判断用户登录状态是否过期是保障用户体验的关键环节。这一过程涉及到服务器与前端之间的紧密协作 , 以及多种技术手段的综合运用 , 还是蛮有挑战性的。
判断登录过期的主要方法有: 检查令牌有效期 , 定时轮询服务器 , 全局请求拦截器 , 利用web存储中的时间戳。
一、检查令牌有效期
对于包含有效期信息的令牌(如 JWT 中的exp字段),前端可以在每次发送请求之前对令牌进行检查。以下是一个简单的检查 JWT 令牌有效期的函数示例(使用jwt-decode库来解析 JWT):
import jwt_decode from 'jwt-decode';
function checkTokenValidity(token) {
try {
const decodedToken = jwt_decode(token);
const currentTime = Date.now() / 1000; // 获取当前时间(以秒为单位)
if (decodedToken.exp < currentTime) {
console.log('令牌已过期(令牌有效期检查)');
return false;
}
return true;
} catch (error) {
console.log('令牌解析出错:', error);
return false;
}
}
// 在发送请求前调用此函数检查令牌
const token = localStorage.getItem('token');
if (checkTokenValidity(token)) {
// 令牌有效,继续发送请求
// 这里假设使用`axios`发送请求
axios.get('/api/data');
} else {
console.log('登录状态可能已过期,需处理');
// 处理登录过期情况,如提示用户重新登录
}
二、定时轮询服务器
轮询服务器状态是一种主动检查令牌是否有效的方法。前端可以定期发送请求到服务器,检查令牌是否仍然有效。
1. 定时轮询
设置一个定时器,每隔一定时间发送请求到服务器,检查令牌状态:
function checkTokenStatus() {
axios.get('/auth/check')
.then(response => {
if (!response.data.valid) {
// 令牌无效,执行登出逻辑
logout();
}
})
.catch(error => {
// 网络错误或其他问题,执行登出逻辑
logout();
});
}
setInterval(checkTokenStatus, 15 * 60 * 1000); // 每15分钟检查一次
2.优化轮询频率
需求背景: 在企业级应用中,可能会有大量用户同时在线,频繁的过期检测操作(如定时轮询)会对系统性能造成过大的负担。因此,需要采用高效的过期检测机制,例如优化轮询的频率,或者采用更智能的令牌有效期检查算法,减少不必要的检测次数。
为了减少对服务器的压力,可以根据用户的操作频率调整轮询频率。例如,在用户活跃时频繁检查,在用户长时间没有操作时减少检查频率。
let lastActivityTime = Date.now();
document.addEventListener('mousemove', () => lastActivityTime = Date.now());
document.addEventListener('keydown', () => lastActivityTime = Date.now());
setInterval(() => {
if (Date.now() - lastActivityTime < 5 * 60 * 1000) { // 用户5分钟内有操作
checkTokenStatus();
}
}, 15 * 60 * 1000);
这种方法可以在确保安全性的同时减少对服务器的压力。
三、全局请求拦截器
前端在发送请求时,可以通过检查服务器的响应状态码来判断登录是否过期。通常,服务器会返回401未授权状态码表示令牌无效或过期。
1. 捕获401状态码
axios.interceptors.response.use(response => {
return response;
}, error => {
if (error.response.status === 401) {
// 令牌无效或过期,执行登出逻辑
logout();
}
return Promise.reject(error);
});
2.弹出登录提示
当捕获到401状态码时 , 可以弹出登录提示 , 引导用户重新登录:
function logout() {
// 清除本地存储的令牌
removeToken();
// 弹出登录提示
alert('登录已过期,请重新登录');
// 跳转到登录页面
window.location.href = '/login';
}
这种方法可以确保前端在令牌过期时及时响应,提高了系统的安全性。
四、利用web中的持久化存储
前端可以在登录成功时将令牌的有效期时间戳保存到Web存储(如localStorage或sessionStorage),并在每次请求前检查时间戳是否过期。
1.保存时间戳
在用户登录成功后 , 将令牌和有效期时间戳保存到 localStorage
中:
function saveToken(token, expiresIn) {
const expirationTime = Date.now() + expiresIn * 1000;
localStorage.setItem('token', token);
localStorage.setItem('tokenExpiration', expirationTime);
}
2.检查时间戳
在每次请求前,检查当前时间是否超过保存的时间戳:
function isTokenExpired() {
const expirationTime = localStorage.getItem('tokenExpiration');
return Date.now() >= expirationTime;
}
如果时间戳过期,则提示用户重新登录:
axios.interceptors.request.use(config => {
if (isTokenExpired()) {
// 令牌过期,执行登出逻辑
logout();
} else {
const token = localStorage.getItem('token');
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
}, error => {
return Promise.reject(error);
});
特定场景中的优化方案
前面都是检测用户登录状态的方法 , 这个时候 产品经理
提出一个需要优化的点:
需求背景: 在业务流程中,用户可能正在进行重要的操作(如填写复杂的表单、进行数据分析等)。当登录状态过期时,应尽量避免突然中断用户操作,如在不影响用户当前输入的情况下弹出提示框,引导用户重新登录。
那我们如何实现这个需求呢? 答案是--------优雅降级
当检测到登录状态过期时,为了避免给用户带来突兀的体验,我们需要采用优雅降级的方式。例如,可以通过模态框提示用户登录过期信息,并允许用户重新登录,同时要保留当前页面的状态。以下是一个使用 React.js 实现的简单示例(使用react-bootstrap
的模态框组件):
首先,确保项目中已经安装了react-bootstrap
和react-router-dom
库。
import React, { useState } from 'react';
import { Button, Modal } from 'react-bootstrap';
import { useHistory } from 'react-router-dom';
const LoginExpiredModal = () => {
const [dialogVisible, setDialogVisible] = useState(false);
const history = useHistory();
// 这里模拟存储当前页面的一些状态信息,比如表单数据等
const currentPageState = {
formData: { name: 'John', age: 30 }
};
const showModal = () => {
setDialogVisible(true);
};
const handleClose = () => {
// 将当前页面状态存储到localStorage中
localStorage.setItem('pageState', JSON.stringify(currentPageState));
// 重定向到登录页面
history.push('/login');
};
return (
<div>
<Button onClick={showModal}>模拟触发登录过期提示</Button>
<Modal show={dialogVisible} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>登录过期</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>您的登录已过期,请重新登录。</p>
</Modal.Body>
</Modal>
</div>
);
};
export default LoginExpiredModal;
标签:令牌,const,登录,过期,前端,用户,token
From: https://blog.csdn.net/Mz0127/article/details/143377054