news 2026/8/22 17:52:34

Vue3 登录状态持久化方案(附:Token 是什么)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue3 登录状态持久化方案(附:Token 是什么)

Vue3中登录状态刷新后消失的原因在于内存数据重置。


解决方案包括:

  1. 使用localStorage存储token和用户信息;
  2. 通过Pinia持久化插件自动保存状态;
  3. 组合式API封装认证逻辑;
  4. 配合路由守卫控制访问权限;
  5. 使用Cookie支持SSR。

最佳实践建议采用双重存储策略(Vuex+localStorage+sessionStorage),并注意安全性和自动刷新token机制。


根据项目需求(SPA/SSR/安全级别)选择合适的持久化方案。


token 通常是 JWT(JSON Web Token)格式的字符串


Vue3登录状态持久化方案


为什么刷新后登录状态会消失?

在 Vue3 项目中,登录状态通常保存在内存中(如 Vuex/Pinia 的状态、组件的响应式数据)。当页面刷新时:

  1. 内存数据被清空- 浏览器重新加载页面,JavaScript 环境重置

  2. Vue 应用重新初始化- store 和组件状态恢复为初始值

  3. HTTP 请求是无状态的- 服务器不会自动记住客户端状态


如何持久化登录状态

方案一:Token + localStorage(最常用)

// 1. 登录成功后保存 token import { ref } from 'vue' const login = async () => { const response = await api.login(username, password) if (response.success) { // 保存到 localStorage localStorage.setItem('token', response.data.token) localStorage.setItem('userInfo', JSON.stringify(response.data.user)) // 同时保存到 Vue 状态管理 userStore.setUser(response.data.user) userStore.setToken(response.data.token) } } // 2. 应用初始化时恢复状态 import { onMounted } from 'vue' import { useUserStore } from '@/stores/user' const userStore = useUserStore() onMounted(() => { // 从 localStorage 恢复 const token = localStorage.getItem('token') const userInfo = localStorage.getItem('userInfo') if (token && userInfo) { userStore.setToken(token) userStore.setUser(JSON.parse(userInfo)) } })

方案二:使用 Vuex/Pinia 持久化插件

安装pinia-plugin-persistedstate

npm install pinia-plugin-persistedstate

配置:

// main.js / main.ts import { createPinia } from 'pinia' import { createPersistedState } from 'pinia-plugin-persistedstate' const pinia = createPinia() pinia.use(createPersistedState({ storage: localStorage, // 或使用 sessionStorage // storage: sessionStorage, // 自定义序列化(可选) serializer: { serialize: JSON.stringify, deserialize: JSON.parse, }, // 自动恢复所有 store auto: true })) app.use(pinia)

使用:

// stores/user.js import { defineStore } from 'pinia' export const useUserStore = defineStore('user', { state: () => ({ token: '', userInfo: null }), actions: { login(data) { this.token = data.token this.userInfo = data.user }, logout() { this.token = '' this.userInfo = null } }, // 启用持久化 persist: { key: 'user', // 存储的 key storage: localStorage, paths: ['token', 'userInfo'] // 只持久化这些字段 } })

方案三:组合式 API 封装

// composables/useAuth.js import { ref, onMounted } from 'vue' import { useRouter } from 'vue-router' export function useAuth() { const token = ref('') const user = ref(null) const router = useRouter() // 登录 const login = async (credentials) => { const response = await api.login(credentials) setAuth(response.data) } // 设置认证信息 const setAuth = (data) => { token.value = data.token user.value = data.user // 保存到 localStorage localStorage.setItem('auth_token', data.token) localStorage.setItem('auth_user', JSON.stringify(data.user)) // 设置 axios 默认请求头 api.setAuthToken(data.token) } // 登出 const logout = () => { token.value = '' user.value = null localStorage.removeItem('auth_token') localStorage.removeItem('auth_user') api.clearAuthToken() router.push('/login') } // 初始化检查登录状态 const initAuth = () => { const savedToken = localStorage.getItem('auth_token') const savedUser = localStorage.getItem('auth_user') if (savedToken && savedUser) { token.value = savedToken user.value = JSON.parse(savedUser) api.setAuthToken(savedToken) } } // 检查是否已登录 const isAuthenticated = () => { return !!token.value } return { token, user, login, logout, initAuth, isAuthenticated } }

方案四:配合路由守卫

// router/index.js import { createRouter, createWebHistory } from 'vue-router' const routes = [ { path: '/dashboard', component: () => import('@/views/Dashboard.vue'), meta: { requiresAuth: true } }, { path: '/login', component: () => import('@/views/Login.vue'), meta: { guestOnly: true } } ] const router = createRouter({ history: createWebHistory(), routes }) // 路由守卫 router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') // 需要认证的页面 if (to.meta.requiresAuth && !token) { next('/login') return } // 仅游客可访问的页面(如登录页) if (to.meta.guestOnly && token) { next('/dashboard') return } next() })

方案五:使用 Cookie(服务端渲染友好)

// 使用 js-cookie 库 import Cookies from 'js-cookie' // 保存 token Cookies.set('token', response.data.token, { expires: 7, // 7天后过期 secure: true, // HTTPS only sameSite: 'strict' }) // 读取 token const token = Cookies.get('token')

最佳实践建议

  1. 双重存储策略

    // 同时使用多种存储方式 const saveAuth = (data) => { // 1. Vuex/Pinia store.setAuth(data) // 2. localStorage(主要持久化) localStorage.setItem('auth', JSON.stringify(data)) // 3. sessionStorage(标签页内有效) sessionStorage.setItem('auth_temp', JSON.stringify(data)) // 4. Cookie(SSR 需要) Cookies.set('token', data.token, { expires: 7 }) }
  2. 安全考虑

    • 对于敏感信息,考虑使用sessionStorage(标签页关闭即清除)

    • 或者使用加密存储:npm install crypto-js

    import CryptoJS from 'crypto-js' const encryptData = (data) => { return CryptoJS.AES.encrypt( JSON.stringify(data), 'your-secret-key' ).toString() }
  3. 自动刷新 Token

    // 定期刷新 token setInterval(async () => { if (isAuthenticated()) { const newToken = await api.refreshToken() localStorage.setItem('token', newToken) } }, 30 * 60 * 1000) // 每30分钟

选择哪种方案取决于你的具体需求:

  • 纯 SPA 应用:localStorage + Pinia 持久化插件

  • 需要 SSR:Cookie + 服务端状态同步

  • 高安全要求:短期 sessionStorage + 定期刷新 Token


简要说明:Token 是什么?


Token(令牌)是一个用于身份验证授权的字符串凭证,类似现实生活中的“门禁卡”或“钥匙”。


核心特点

  1. 令牌形式:通常是 JWT(JSON Web Token)格式的字符串

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NSIsImlhdCI6MTYxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  2. 无状态:服务器不需要存储 session,自身包含用户信息

  3. 自包含:Token 本身包含了用户身份信息和过期时间


Token 的工作流程(以登录为例)

用户登录 → 服务器验证 → 生成Token → 返回给客户端 ↓ 客户端存储Token → 后续请求携带Token → 服务器验证Token → 返回数据

Token 的结构(JWT 为例)

一个典型的 Token 包含三部分:

头部.载荷.签名

示例解析:

// 1. 头部(Header)- 说明令牌类型和算法 { "alg": "HS256", // 签名算法 "typ": "JWT" // 令牌类型 } // 2. 载荷(Payload)- 包含实际数据(用户信息等) { "userId": "12345", "username": "张三", "exp": 1640995200 // 过期时间戳 } // 3. 签名(Signature)- 用于验证令牌真伪 HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

为什么使用 Token?

优点:

  • 无状态:服务器不需要维护 session 存储

  • 跨域友好:适合前后端分离和 API 调用

  • 移动端兼容:适合 App、小程序等

  • 可扩展性:容易实现分布式系统

缺点:

  • Token 泄露风险:一旦被盗用,攻击者可以冒充用户

  • 无法立即失效:需要额外的黑名单机制

  • 存储安全问题:需要安全的存储方式(localStorage 有 XSS 风险)


Token vs Cookie

特性TokenCookie
存储位置localStorage / 内存浏览器自动管理
跨域请求手动添加到 Header自动携带
安全性易受 XSS 攻击易受 CSRF 攻击
移动端支持有限

实际应用示例

// 客户端:存储和发送 Token localStorage.setItem('token', 'your-jwt-token') // 发送请求时携带 Token fetch('/api/user', { headers: { 'Authorization': `Bearer ${localStorage.getItem('token')}` } }) // 服务器端:验证 Token app.get('/api/protected', (req, res) => { const token = req.headers.authorization?.split(' ')[1] if (!token) return res.status(401).send('无权限') // 验证 Token 是否有效 const decoded = jwt.verify(token, 'secret-key') // 如果有效,处理请求... })

设置axios的通用头

App.vue

<template> <div class="container"> <Loader v-if="isLoading" text="正在加载😊" background="rgba(0,0,0,0.8)"></Loader> <global-header :user="currentUser"></global-header> <router-view></router-view> <footer class="text-center py-4 text-secondary bg-light mt-6"> <small> ...... </small> </footer> </div> </template> <script lang="ts" setup> import 'bootstrap/dist/css/bootstrap.min.css' import GlobalHeader from './components/GlobalHeader.vue' import { computed, onMounted } from 'vue' import { useStore } from 'vuex' import Loader from './components/Loader.vue' import axios from 'axios' const store = useStore() const currentUser = computed(() => { return store.state.user }) const isLoading = computed(() => { return store.state.loading }) //获取store中的token const token = computed(() => { return store.state.token }) onMounted(() => { //持久化登录状态 //判断用户是否登录 if (!currentUser.value.isLogin && token.value) { //如果没登录,但是有token //设置axios的通用头 axios.defaults.headers.common['Authorization'] = `Bearer ${token.value}` //获取用户信息 store.dispatch('fetchCurrentUser') } }) </script>

一句话总结:Token 是一种数字钥匙,客户端持有它来证明自己的身份,服务器通过验证这把钥匙的真伪来决定是否提供服务。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/20 21:45:58

2026 数据分析主流语言全景解析:选型、场景与学习路径

在数据驱动决策成为企业核心竞争力的当下&#xff0c;数据分析语言早已从专业工具升级为数字化从业者的必备技能。从业务人员的基础取数、分析师的深度挖掘&#xff0c;到数据科学家的模型构建&#xff0c;不同语言凭借独特的技术特性与生态优势&#xff0c;划分出清晰的应用边…

作者头像 李华
网站建设 2026/8/17 12:12:18

Thinkphp和Laravel框架的教学日常管理系统(活动 选课 考勤,听课)

目录 核心功能模块ThinkPHP实现要点Laravel实现要点技术对比差异安全防护措施扩展性设计部署优化方案 开发技术源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01; 以下是关于使用ThinkPHP和Laravel框架开发教学日常管理系统&#xff08;涵…

作者头像 李华
网站建设 2026/8/22 0:00:27

计算机毕业设计springboot辅导员职责信息管理系统 基于Spring Boot的高校辅导员工作事务综合平台 Spring Boot驱动的学生事务与辅导员协同管理系统

计算机毕业设计springboot辅导员职责信息管理系统_6g45l &#xff08;配套有源码 程序 mysql数据库 论文&#xff09; 本套源码可以在文本联xi,先看具体系统功能演示视频领取&#xff0c;可分享源码参考。 高校日常育人工作中&#xff0c;辅导员需要同步跟踪学生的学业、考勤、…

作者头像 李华
网站建设 2026/8/19 16:25:58

全自动汽油氧化安定性测定仪的技术解析与应用价值研究

引言 汽油的氧化安定性是其储存与使用过程中的关键性能指标&#xff0c;直接关系到油品质量、发动机运行效率及环保表现。传统的手动测定方法依赖人工操作与经验判断&#xff0c;存在效率低、重复性差、人为误差大等问题。随着分析检测技术的进步&#xff0c;全自动汽油氧化安…

作者头像 李华
网站建设 2026/8/19 16:21:53

深度测评8个降AIGC网站,千笔·降AIGC助手解决论文AI率过高难题

AI降重工具&#xff0c;为论文保驾护航 在当前学术写作中&#xff0c;随着AI技术的广泛应用&#xff0c;论文中的AIGC率问题越来越受到重视。许多学生在使用AI辅助写作时&#xff0c;往往会出现内容过于机械化、缺乏原创性的问题&#xff0c;导致查重率居高不下&#xff0c;甚至…

作者头像 李华