2022-02-17 10:49:10
在JavaScript中管理JWT令牌需围绕获取与存储、发送认证、解析验证、清理刷新四个核心环节展开,结合安全实践确保可靠性。 以下是具体实现方法与关键注意事项:
一、获取与安全存储JWT获取方式用户登录成功后,服务器通过HTTP响应返回JWT(通常在响应体或响应头中)。前端使用fetch或axios等库发送登录请求,并从响应中提取令牌:
fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password })}).then(res => res.json()) .then(data => { localStorage.setItem('token', data.token); // 存储到localStorage });存储选择
推荐使用localStorage或sessionStorage:避免使用Cookie(除非设置HttpOnly,但会限制前端读取能力)。
敏感信息处理:JWT的payload中不应存储密码等敏感数据,仅包含用户ID、角色等非敏感信息。
存储期限:若需浏览器关闭后仍保持登录状态,用localStorage;否则用sessionStorage(会话级存储)。
封装请求函数每次请求受保护API时,需在Authorization头中携带JWT(格式为Bearer <token>)。通过封装请求函数实现复用:
function authFetch(url, options = {}) { const token = localStorage.getItem('token'); const headers = { 'Content-Type': 'application/json', ...options.headers, 'Authorization': `Bearer ${token}` }; return fetch(url, { ...options, headers });}// 使用示例authFetch('/api/protected-data').then(res => res.json());拦截器实现(Axios示例)若使用axios,可通过拦截器统一添加认证头:
axios.interceptors.request.use(config => { const token = localStorage.getItem('token'); if (token) config.headers.Authorization = `Bearer ${token}`; return config;});解码PayloadJWT由三部分组成(header.payload.signature),可通过Base64解码获取payload中的用户信息(如过期时间exp):
function parseJwt(token) { const payload = token.split('.')[1]; return JSON.parse(atob(payload));}const decoded = parseJwt(localStorage.getItem('token'));console.log(decoded.exp); // 过期时间戳(Unix时间)前端验证的局限性
不可完全信任前端验证:前端解码仅用于展示用户信息或提示过期,实际权限验证需由后端完成。
过期时间处理:前端可检查exp判断令牌是否即将过期,提前刷新或提示用户重新登录。
主动登出用户登出时,清除本地存储的令牌并跳转到登录页:
function logout() { localStorage.removeItem('token'); window.location.href = '/login';}自动刷新机制
配合Refresh Token:后端可提供刷新接口(如/api/refresh-token),前端在令牌过期前发送刷新请求获取新令牌。
实现逻辑:
存储refreshToken(通常与accessToken分开存储)。
检测到accessToken过期时,用refreshToken请求新accessToken。
更新本地存储并重试原请求。
async function refreshTokenAndRetry(originalRequest) { const refreshToken = localStorage.getItem('refreshToken'); const res = await fetch('/api/refresh-token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refreshToken }) }); const data = await res.json(); localStorage.setItem('token', data.newAccessToken); return authFetch(originalRequest.url, originalRequest.options);}监听路由或定时检查
路由变化:在单页应用(SPA)中,监听路由变化触发令牌有效性检查。
定时检查:设置定时器定期验证令牌状态(如每5分钟检查一次)。
对用户输入进行严格过滤和转义。
使用内容安全策略(CSP)限制脚本执行来源。
前端JWT管理的核心流程为:获取→存储→发送→解析→清理,需结合安全实践(如HTTPS、短有效期、防XSS)降低风险。虽然无法完全杜绝攻击,但通过规范操作可显著提升安全性。