前端如何检测用户登录状态是否过期

news/2024/12/22 23:33:29/

前端开发中 , 判断用户登录状态是否过期是一个常见的需求。尤其是在复杂的场景中 , 准确判断用户登录状态是否过期是保障用户体验的关键环节。这一过程涉及到服务器与前端之间的紧密协作 , 以及多种技术手段的综合运用 , 还是蛮有挑战性的。

判断登录过期的主要方法有: 检查令牌有效期 , 定时轮询服务器 , 全局请求拦截器 , 利用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-bootstrapreact-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;

http://www.ppmy.cn/news/1557321.html

相关文章

构建一个rust生产应用读书笔记6-拒绝无效订阅者02

打破域子模块 通常指的是对应用程序的某个特定业务领域进行重构或重新组织。这可能包括拆分、合并或重组代码结构以更好地反映业务规则和逻辑。下面是一些关于如何处理这种情况的建议&#xff1a; 1. 理解当前状态 首先&#xff0c;确保你完全理解现有系统的工作方式。这包括…

Java项目--仿RabbitMQ的消息队列--内存数据管理

目录 一、引言 二、MemoryDataCenter 1.设计数据结构 2.封装Exchange方法 3.封装MsgQueue方法 4.封装Binding方法 5.封装Message 6.实现待确定消息的管理 7.将数据从硬盘上恢复到内存中 三、测试MemoryDataCenter 1.准备工作 2.测试交换机 3.测试队列 4.测试绑定 …

Go, Jocko, Kafka

本篇内容是根据2016年8月份# 31. Go, Jocko, Kafka 音频录制内容的整理与翻译 Travis Jeffery 参加了节目&#xff0c;谈论 Go、Jocko、Kafka、Kafka 的存储内部结构如何工作&#xff0c;以及有趣的 Go 项目和新闻。 Erik St. Martin: 大家好&#xff0c;欢迎回到《GoTime》的另…

建站经验:服务器同步与数据库备份的终极解决方案

兼容宝塔面板&#xff0c;请按照步骤来配置 一键部署脚本 curl -sS -O https://raw.githubusercontent.com/woniu336/open_shell/main/rsync-vps.sh && chmod x rsync-vps.sh && ./rsync-vps.sh注意事项 提示&#xff08;宝塔面板&#xff09;&#xff1a;两…

对 MYSQL 架构的了解

MySQL 是一种广泛使用的关系型数据库管理系统&#xff0c;其架构主要包括以下几个关键部分&#xff1a; 一、连接层 客户端连接管理&#xff1a;MySQL 服务器可以同时处理多个客户端的连接请求。当客户端应用程序&#xff08;如使用 Java、Python 等语言编写的程序&#xff09;…

K8s中 statefulset 和deployment的区别

在 Kubernetes 中&#xff0c;StatefulSet 和 Deployment 是两种管理 Pod 的控制器&#xff0c;它们的主要区别在于 状态管理 和 Pod 的标识。以下是详细对比&#xff1a; 1. 功能定位 Deployment 用途&#xff1a;用于 无状态应用 的部署&#xff0c;例如 Web 服务、API 服务…

【LuaFramework】服务器模块相关知识

目录 一、客户端代码 二、本地服务器代码 三、解决服务器无法多次接收客户端消息问题 一、客户端代码 连接本地服务器127.0.0.1:2012端口&#xff08;如何创本地服务器&#xff0c;放最后说&#xff09;&#xff0c;连接成功后会回调 协议号Connect是101&#xff0c;其他如下…

霍特林分布

内容来源 应用多元统计分析 北京大学出版社 高惠璇编著 霍特林 T 2 T^2 T2 分布 一元统计中&#xff0c;若 X ∼ N ( 0 , 1 ) X\sim N(0,1) X∼N(0,1) ξ ∼ χ 2 ( n ) \xi\sim\chi^2(n) ξ∼χ2(n) 且 X X X 与 ξ \xi ξ 相互独立&#xff0c;则 t X ξ / n ∼ t ( n …