/** * 认证相关工具函数 * 包含JWT token管理、自动刷新、请求拦截等功能 */ const config = require('./config'); const eventManager = require('./eventManager'); // Token刷新状态 let isRefreshing = false; // 等待token刷新的请求队列 let refreshSubscribers = []; /** * 订阅Token刷新 * @param {Function} callback - Token刷新后的回调函数 */ const subscribeTokenRefresh = (callback) => { refreshSubscribers.push(callback); }; /** * 执行Token刷新后的回调 * @param {string} token - 新的access token */ const onTokenRefreshed = (token) => { refreshSubscribers.forEach(callback => callback(token)); refreshSubscribers = []; }; /** * 解析JWT Token * @param {string} token - JWT token * @returns {Object|null} 解析后的payload或null */ const parseToken = (token) => { try { const [, payload] = token.split('.'); return JSON.parse(atob(payload)); } catch (error) { console.error('Token解析失败:', error); return null; } }; /** * 检查Token是否需要刷新 * @param {string} token - JWT token * @returns {boolean} 是否需要刷新 */ const shouldRefreshToken = (token) => { const decoded = parseToken(token); if (!decoded || !decoded.exp) return true; const expiresIn = decoded.exp * 1000 - Date.now(); return expiresIn < config.JWT_CONFIG.refreshThreshold; }; /** * 刷新Token * @returns {Promise} 新的access token或null */ const refreshToken = async () => { const refreshToken = wx.getStorageSync(config.JWT_CONFIG.storage.refresh); if (!refreshToken) return null; try { const response = await wx.request({ url: `${config.API_BASE_URL}${config.API_ENDPOINTS.AUTH.REFRESH}`, method: 'POST', header: { [config.JWT_CONFIG.headerKey]: `${config.JWT_CONFIG.tokenPrefix}${refreshToken}` } }); if (response.statusCode === 200 && response.data.access_token) { const { access_token, refresh_token } = response.data; wx.setStorageSync(config.JWT_CONFIG.storage.access, access_token); if (refresh_token) { wx.setStorageSync(config.JWT_CONFIG.storage.refresh, refresh_token); } return access_token; } throw new Error(response.data?.message || '刷新Token失败'); } catch (error) { console.error('刷新Token失败:', error); logout(); // 刷新失败时登出 return null; } }; /** * 用户登录 * @param {string} username - 用户名 * @param {string} password - 密码 * @returns {Promise} 登录结果,包含success和message字段 */ const login = async (username, password) => { try { const response = await wx.request({ url: `${config.API_BASE_URL}${config.API_ENDPOINTS.AUTH.LOGIN}`, method: 'POST', data: { username, password } }); if (response.statusCode === 200 && response.data.access_token) { const { access_token, refresh_token } = response.data; wx.setStorageSync(config.JWT_CONFIG.storage.access, access_token); wx.setStorageSync(config.JWT_CONFIG.storage.refresh, refresh_token); // 触发登录成功事件 eventManager.emit('auth:login', parseToken(access_token)); return { success: true, message: '登录成功' }; } return { success: false, message: response.data?.message || '登录失败' }; } catch (error) { console.error('登录失败:', error); return { success: false, message: '网络错误,请稍后重试' }; } }; /** * 用户登出 */ const logout = () => { // 清除所有认证信息 wx.removeStorageSync(config.JWT_CONFIG.storage.access); wx.removeStorageSync(config.JWT_CONFIG.storage.refresh); // 触发登出事件 eventManager.emit('auth:logout'); }; /** * 检查用户是否已登录 * @returns {boolean} 是否已登录 */ const isLoggedIn = () => { const token = wx.getStorageSync(config.JWT_CONFIG.storage.access); if (!token) return false; try { // 解析JWT token(不验证签名) const [, payload] = token.split('.'); const { exp } = JSON.parse(atob(payload)); // 检查token是否已过期 return Date.now() < exp * 1000; } catch (error) { console.error('Token解析失败:', error); return false; } }; /** * 获取当前用户信息 * @returns {Object|null} 用户信息或null */ const getCurrentUser = () => { const token = wx.getStorageSync(config.JWT_CONFIG.storage.access); if (!token) return null; try { // 解析JWT token(不验证签名) const [, payload] = token.split('.'); const decoded = JSON.parse(atob(payload)); return { id: decoded.sub, username: decoded.username, // 其他用户信息... }; } catch (error) { console.error('获取用户信息失败:', error); return null; } }; /** * 获取访问令牌 * @param {boolean} autoRefresh - 是否自动刷新 * @returns {Promise} 访问令牌或null */ const getAccessToken = async (autoRefresh = true) => { const token = wx.getStorageSync(config.JWT_CONFIG.storage.access); if (!token) return null; // 检查是否需要刷新token if (autoRefresh && shouldRefreshToken(token)) { if (isRefreshing) { // 如果正在刷新,返回一个Promise等待刷新完成 return new Promise(resolve => { subscribeTokenRefresh(newToken => { resolve(newToken); }); }); } isRefreshing = true; const newToken = await refreshToken(); isRefreshing = false; if (newToken) { onTokenRefreshed(newToken); return newToken; } // 刷新失败,清除token logout(); return null; } return token; }; /** * 创建请求拦截器 * @returns {Function} 请求拦截器函数 */ const createRequestInterceptor = () => { const originalRequest = wx.request; // 重写wx.request方法 wx.request = function(options) { const { url, header = {}, ...restOptions } = options; // 判断是否需要添加认证头 const isAuthUrl = url.includes(config.API_BASE_URL) && !url.includes(config.API_ENDPOINTS.AUTH.LOGIN); if (isAuthUrl) { // 创建一个Promise来处理认证 return new Promise(async (resolve, reject) => { try { const token = await getAccessToken(); if (!token) { // 没有token且需要认证,触发未授权事件 eventManager.emit('auth:unauthorized'); reject(new Error('未授权,请先登录')); return; } // 添加认证头 const authHeader = { ...header, [config.JWT_CONFIG.headerKey]: `${config.JWT_CONFIG.tokenPrefix}${token}` }; // 发送请求 originalRequest({ ...restOptions, url, header: authHeader, success: resolve, fail: reject }); } catch (error) { reject(error); } }); } // 不需要认证的请求直接发送 return originalRequest(options); }; return () => { // 恢复原始请求方法 wx.request = originalRequest; }; }; /** * 初始化认证模块 */ const initAuth = () => { createRequestInterceptor(); // 监听网络状态变化 wx.onNetworkStatusChange(function(res) { if (res.isConnected && isLoggedIn()) { // 网络恢复且已登录,尝试刷新token getAccessToken(); } }); console.log('认证模块初始化完成'); }; module.exports = { login, logout, isLoggedIn, getCurrentUser, getAccessToken, initAuth, parseToken, shouldRefreshToken };