一、JWT认证概述
JWT(JSON Web Token)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为JSON对象。其核心优势在于无状态性,服务器不需要存储会话信息,仅通过验证Token即可确认用户身份。典型应用场景包括API认证、单点登录等。
一个标准的JWT由三部分组成:Header(头部)、Payload(载荷)、Signature(签名),通过Base64URL编码后以点号分隔。在Vue3项目中,JWT通常由后端接口返回,前端负责存储、携带和刷新。
二、Vue3实现登录获取Token
1. 登录接口设计
前端通过表单提交用户名密码至认证接口,后端验证成功后返回JWT。响应数据结构建议如下:
{"code": 200,"data": {"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...","expiresIn": 3600}}
其中accessToken用于API请求认证,refreshToken用于获取新Token,expiresIn表示有效时间(秒)。
2. 登录组件实现
使用Vue3的Composition API构建登录表单:
<template><form @submit.prevent="handleSubmit"><input v-model="form.username" placeholder="用户名" /><input v-model="form.password" type="password" placeholder="密码" /><button type="submit">登录</button></form></template><script setup>import { ref } from 'vue';import { useRouter } from 'vue-router';import { login } from '@/api/auth';import { setTokens } from '@/utils/auth';const router = useRouter();const form = ref({ username: '', password: '' });const handleSubmit = async () => {try {const res = await login(form.value);setTokens(res.data);router.push('/dashboard');} catch (error) {console.error('登录失败:', error);}};</script>
三、Token存储与管理
1. 存储方案选择
- localStorage:持久化存储,适合长期保存Token
- sessionStorage:页面关闭即清除,适合敏感操作
- 内存存储:仅当前组件有效,安全性最高
推荐组合方案:
// utils/auth.jsexport const setTokens = ({ accessToken, refreshToken }) => {localStorage.setItem('accessToken', accessToken);localStorage.setItem('refreshToken', refreshToken);// 可选:内存中保存过期时间sessionStorage.setItem('tokenExpire', Date.now() + 3600 * 1000);};export const getAccessToken = () => localStorage.getItem('accessToken');
2. 安全注意事项
- 避免XSS攻击:使用
secure和httpOnly标志(需配合cookie) - 敏感操作使用短期Token
- 定期清理过期Token
四、自动刷新Token实现
1. 刷新机制设计
当accessToken过期时,使用refreshToken获取新Token。典型流程:
- 请求拦截器检测Token过期
- 调用刷新接口获取新Token
- 重新发起原始请求
2. 具体实现
创建Token服务类
// services/tokenService.jsimport { getRefreshToken } from '@/utils/auth';import { refreshToken } from '@/api/auth';let isRefreshing = false;let subscribers = [];export const subscribeTokenRefresh = (callback) => {subscribers.push(callback);};export const notifySubscribers = (newToken) => {subscribers.forEach(cb => cb(newToken));subscribers = [];};export const getNewToken = async () => {if (isRefreshing) {return new Promise(resolve => {subscribeTokenRefresh((token) => resolve(token));});}isRefreshing = true;try {const res = await refreshToken({refreshToken: getRefreshToken()});// 更新存储的TokensetTokens(res.data);notifySubscribers(res.data.accessToken);return res.data.accessToken;} finally {isRefreshing = false;}};
请求拦截器实现
// utils/request.jsimport axios from 'axios';import { getAccessToken, clearTokens } from './auth';import { getNewToken } from '@/services/tokenService';const service = axios.create({baseURL: process.env.VUE_APP_API_BASE_URL,timeout: 5000});// 请求拦截器service.interceptors.request.use(async (config) => {const token = getAccessToken();if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;},(error) => Promise.reject(error));// 响应拦截器service.interceptors.response.use((response) => response,async (error) => {const { response } = error;if (response?.status === 401) {try {const newToken = await getNewToken();// 重新发起原始请求error.config.headers.Authorization = `Bearer ${newToken}`;return service(error.config);} catch (refreshError) {clearTokens();window.location.href = '/login';return Promise.reject(refreshError);}}return Promise.reject(error);});export default service;
五、最佳实践与优化
1. 性能优化
- 刷新Token时使用请求队列,避免并发刷新
- 设置合理的Token过期时间(建议accessToken 1小时,refreshToken 7天)
- 使用指数退避策略处理刷新失败
2. 错误处理
- 捕获Token无效(401)和刷新失败(403)
- 提供友好的用户提示
- 实现自动登出机制
3. 测试建议
- 模拟Token过期场景
- 测试并发请求下的刷新行为
- 验证边界条件(如网络中断)
六、完整流程示例
- 用户登录 → 存储accessToken/refreshToken
- 发起API请求 → 携带accessToken
- Token过期 → 拦截器触发刷新
- 获取新Token → 重试原始请求
- 刷新失败 → 跳转登录页
通过这种设计,Vue3应用可以实现无缝的JWT认证体验,同时保证安全性。实际项目中可根据需求调整刷新策略,如使用滑动会话(Sliding Session)机制延长用户会话。
七、总结
本文详细介绍了Vue3中实现JWT认证的完整方案,包括Token获取、存储、自动刷新等关键环节。通过合理的架构设计和错误处理,可以构建出健壮的前端认证体系。实际开发中建议结合具体业务场景进行调整,并始终将安全性放在首位。