尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于 Vue3 实现用户闲置自动退出登录方案

基于 Vue3 实现用户闲置自动退出登录方案 一、方案背景在后台管理系统、企业级中台等权限管控严格的场景中用户长时间未操作设备易造成账号未锁屏、信息泄露、越权访问等安全风险。为满足系统安全规范需实现用户闲置超时自动登出能力当用户连续无操作达到指定时长系统自动清空登录态、跳转至登录页杜绝未授权访问隐患。本文基于Vue3 Composition API封装通用、可复用的useIdleLogout组合式函数实现高适配、高稳定性的闲置监控能力并完成全局优雅集成同时解决跨标签页同步、页面刷新恢复、动态配置超时时间等核心痛点。二、需求分析结合业务安全要求与前端交互场景闲置自动登出方案需满足以下核心需求精准定义用户闲置状态监听键盘输入、鼠标点击、页面滚动、移动端触摸等用户主动操作以此判定用户是否处于活跃状态。超时时间动态可配置闲置超时时长由后端接口下发用户配置前端不硬编码支持不同用户、不同环境灵活适配。跨标签页/窗口状态同步用户多标签页同时登录系统时所有页面共享用户活跃状态一处操作全局更新一处超时全局登出。登录状态差异化管控未登录状态下禁用闲置监控仅用户登录成功后自动启动监控逻辑。页面刷新状态恢复页面刷新后不重置计时自动读取历史活跃时间若刷新前已超时则直接登出规避安全漏洞。性能与稳定性保障避免事件重复绑定、内存泄漏、重复登出等问题适配长期运行的后台系统。三、核心设计思路3.1 状态分层设计事件绑定 逻辑启用分离将监控能力拆分为「事件预绑定」和「校验逻辑启用」两个阶段解耦初始化与业务逻辑start()全局预绑定用户操作 DOM 事件仅监听不校验避免后续重复绑定事件。enable()登录成功后触发正式启用闲置超时校验逻辑初始化活跃时间、校验当前是否已超时。该设计可实现应用启动时提前准备监听能力登录后快速激活校验时序更合理、交互更稳定。3.2 跨页面状态同步方案借助localStorage持久化存储用户最后活跃时间戳实现多标签页、多窗口数据共享。所有页面读取同一份时间戳任意页面的用户操作会全局更新时间戳超时后清空存储实现全局同步登出。3.3 刷新场景安全兜底页面刷新后系统会优先读取本地存储的最后活跃时间结合后端下发的超时配置二次校验若已超出闲置时长则直接执行登出逻辑避免刷新重置计时导致的安全隐患。四、核心代码实现4.1 封装闲置监控 Composable新建composables/useIdleLogout.js封装所有闲置校验、状态管理、登出逻辑实现能力复用。import { ref } from vue import useUserStore from /store/modules/user // 本地存储key最后用户活跃时间戳 export const STORAGE_KEY LAST_ACTIVITY_TIMESTAMP // 需要监听的用户活跃事件 const ACTIVITY_EVENTS [keydown, click, scroll, touchstart] /** * 获取最后一次用户活跃时间戳 * returns {number} 时间戳 */ function getLastActivityTime() { const ts localStorage.getItem(STORAGE_KEY) return ts ? parseInt(ts, 10) : 0 } /** * 更新用户最后活跃时间戳 */ function updateLastActivityTime() { localStorage.setItem(STORAGE_KEY, Date.now().toString()) } /** * 校验是否闲置超时 * param {number} idleTimeMs - 超时毫秒数 * returns {boolean} 是否超时 */ function isTimeout(idleTimeMs) { if (!idleTimeMs || idleTimeMs 0) return false const lastActiveTime getLastActivityTime() // 无活跃记录默认不超时 if (lastActiveTime 0) return false return Date.now() - lastActiveTime idleTimeMs } /** * 清空登录态并跳转登录页全局通用方法 */ function clearBrandPrefixAndReloadToLogin() { // 清空路由前缀、缓存、登录标识等全局状态 // 根据项目实际业务补充逻辑 window.location.href /login } export function useIdleLogout() { const userStore useUserStore() let isLoggingOut false // 登出锁防止重复登出 let hasBoundEvents false // 事件绑定锁防止重复绑定 const isEnabled ref(false) // 监控是否启用 /** * 获取后端配置的闲置超时时间转换为毫秒 * returns {number} 超时毫秒数 */ const getIdleTimeMs () { const idleMinutes Number(userStore?.user?.idleLogoutMinutes || 0) return idleMinutes 0 ? idleMinutes * 60 * 1000 : 0 } /** * 执行自动登出逻辑 */ const logout async () { if (isLoggingOut) return isLoggingOut true // 执行全局登出清空逻辑 await userStore.logOut() // 清除活跃时间缓存 localStorage.removeItem(STORAGE_KEY) // 跳转登录页 clearBrandPrefixAndReloadToLogin() // 解锁登出状态 isLoggingOut false } /** * 用户活跃事件回调 */ const onUserActivity () { // 监控未启用不执行任何逻辑 if (!isEnabled.value) return const idleTimeMs getIdleTimeMs() if (!idleTimeMs) return // 已超时则登出否则更新活跃时间 if (isTimeout(idleTimeMs)) { logout() } else { updateLastActivityTime() } } /** * 绑定用户活跃监听事件 */ const bindEvents () { ACTIVITY_EVENTS.forEach(event window.addEventListener(event, onUserActivity)) } /** * 解绑用户活跃监听事件 */ const unbindEvents () { ACTIVITY_EVENTS.forEach(event window.removeEventListener(event, onUserActivity)) } /** * 启动监控仅绑定事件不启用校验逻辑 */ const start () { if (hasBoundEvents) return bindEvents() hasBoundEvents true } /** * 停止监控解绑事件、关闭校验 */ const stop () { isEnabled.value false if (!hasBoundEvents) return unbindEvents() hasBoundEvents false } /** * 启用闲置超时校验登录成功后调用 */ const enable () { if (isEnabled.value) return const idleTimeMs getIdleTimeMs() // 后端未配置超时时间不启用监控 if (!idleTimeMs) return // 页面刷新后校验是否已超时 if (isTimeout(idleTimeMs)) { logout() return } // 初始化活跃时间启用监控 updateLastActivityTime() isEnabled.value true } return { start, stop, enable } }4.2 全局初始化配置App.vue在根组件中完成监控能力初始化、全局方法挂载、未登录状态缓存清理保证全局唯一性。script setup import { onMounted } from vue import { useIdleLogout, STORAGE_KEY } from /composables/useIdleLogout import { getToken } from /utils/auth // 初始化闲置监控方法 const { start, stop, enable } useIdleLogout() // 挂载至全局供页面、登录逻辑调用 window.__startIdleCheck start window.__stopIdleCheck stop window.__enableIdleCheck enable onMounted(() { // 未登录状态清除残留活跃时间戳避免脏数据干扰 if (!getToken()) { localStorage.removeItem(STORAGE_KEY) } }) /script4.3 主布局集成监控逻辑layout/index.vue在系统核心布局中等待用户信息加载完成后根据后端配置动态启用/关闭闲置监控适配登录后场景。script setup import { onMounted, onUnmounted } from vue import useUserStore from /store/modules/user const userStore useUserStore() // 挂载后根据用户配置初始化监控 onMounted(async () { // 确保用户信息加载完成 if (!userStore?.user?.id) { try { await userStore.getInfo() } catch (error) { // 获取用户信息失败token过期等停止监控 window.__stopIdleCheck?.() return } } // 后端配置超时时间则启用监控否则关闭 const idleMinutes userStore?.user?.idleLogoutMinutes || 0 if (idleMinutes 0) { window.__startIdleCheck?.() window.__enableIdleCheck?.() } else { window.__stopIdleCheck?.() } }) // 组件卸载时清理事件监听防止内存泄漏 onUnmounted(() { window.__stopIdleCheck?.() }) /script五、整体执行流程图解───────────────────────────────────────────────────────────── 应用启动 (App.vue) 1. 初始化 useIdleLogout 监控能力 2. 挂载全局监控方法start/stop/enable 3. 未登录状态 → 清空本地残留活跃时间戳 ───────────────────────────────────────────────────────────── │ ▼ ───────────────────────────────────────────────────────────── 主布局页面挂载初始化 1. 拉取最新用户信息与后端超时配置 2. 配置有效 → 绑定事件、启用超时校验 3. 配置无效/用户信息失败 → 关闭监控 ───────────────────────────────────────────────────────────── │ ▼ ───────────────────────────────────────────────────────────── 用户登录成功场景 调用全局 __enableIdleCheck() 启用监控 ├─ 读取本地最后活跃时间戳 ├─ 已超时 → 自动执行登出、跳转登录页 └─ 未超时 → 更新活跃时间开启实时监控 ───────────────────────────────────────────────────────────── │ ▼ ───────────────────────────────────────────────────────────── 实时闲置监控流程 用户触发操作事件 → 执行 onUserActivity() 更新状态 ├─ 监控启用 已超时 → 执行登出逻辑 └─ 监控启用 未超时 → 刷新本地活跃时间戳 ─────────────────────────────────────────────────────────────六、配置项说明配置项/常量数据来源功能说明idleLogoutMinutes后端用户配置闲置超时分钟数0/undefined 表示关闭自动登出功能STORAGE_KEY前端常量本地存储用户最后活跃时间戳的 key可自定义修改ACTIVITY_EVENTS前端常量监听的用户活跃事件覆盖桌面端、移动端常规操作七、关键注意事项与问题规避7.1 防止内存泄漏所有监听事件必须在页面/组件卸载时统一解绑通过onUnmounted调用stop()方法清空事件监听避免长期运行的后台系统内存累积泄漏。7.2 避免事件重复绑定通过hasBoundEvents状态锁标记事件绑定状态多次调用start()不会重复绑定 DOM 事件杜绝事件叠加、重复触发问题。7.3 防止重复执行登出新增isLoggingOut登出锁多事件同时触发超时逻辑时仅执行一次登出流程避免接口重复请求、页面重复跳转异常。7.4 严格把控执行时序遵循「根组件初始化 - 布局页加载用户配置 - 启用监控」的时序。用户信息获取失败、Token 过期等异常场景主动关闭监控避免无效校验。7.5 浏览器兼容性所使用的keydown、click、scroll、touchstart均为原生标准 DOM 事件兼容所有现代浏览器无需额外垫片适配。八、方案总结本方案基于 Vue3 组合式 API 实现核心优势集中在解耦、安全、可扩展、高适配逻辑解耦复用将闲置监控逻辑封装为独立 Composable与页面视图解耦全局可复用维护成本低。动态配置灵活超时时间由后端动态下发无需修改前端代码可适配不同用户、不同业务场景的安全策略。多页面状态同步基于 localStorage 实现跨标签页、跨窗口状态共享解决多页面登录状态不一致问题。全方位安全兜底覆盖页面刷新、异常登出、重复操作等边界场景彻底规避闲置计时重置的安全漏洞。性能稳定可靠通过多重状态锁规避重复绑定、重复登出、内存泄漏等问题适配系统长期稳定运行。该方案已完成线上全量落地覆盖后台管理系统所有登录页面可直接复用至各类 Vue3 企业级项目。
返回列表