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

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

判断登录过期的主要方法有: 检查令牌有效期 , 定时轮询服务器 , 全局请求拦截器 , 利用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;
相关推荐
崔庆才丨静觅6 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60616 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了6 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅7 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅7 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅7 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment7 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅8 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊8 小时前
jwt介绍
前端
爱敲代码的小鱼8 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax