/** * 认证服务API */ class AuthService { // 本地开发: 'http://localhost:8080/api' // 生产环境: 'http://101.200.154.78:8080/api' static BASE_URL = 'http://localhost:8080/api'; /** * 发送验证码 * @param {string} account - 手机号或邮箱 * @param {string} type - 验证码类型:login/register * @returns {Promise} API响应 */ static async sendVerifyCode(account, type = 'login') { try { const response = await fetch(`${this.BASE_URL}/auth/send-code`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ contact: account // 后端使用contact字段 }) }); const data = await response.json(); // 后端使用code字段判断成功与否,200表示成功 if (data.code !== 200) { throw new Error(data.message || '发送验证码失败'); } return { success: true, data: data.data, message: data.message || '验证码发送成功' }; } catch (error) { console.error('Send verify code failed:', error); return { success: false, message: error.message || '网络错误,请稍后重试' }; } } /** * 用户登录 * @param {string} account - 手机号或邮箱 * @param {string} verifyCode - 验证码 * @returns {Promise} API响应 */ static async login(account, verifyCode) { try { const response = await fetch(`${this.BASE_URL}/auth/login`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ contact: account, // 后端使用contact字段 code: verifyCode // 后端使用code字段 }) }); const data = await response.json(); // 后端使用code字段判断成功与否,200表示成功 if (data.code !== 200) { throw new Error(data.message || '登录失败'); } // 后端响应的数据在data字段中 const authData = data.data; if (authData && authData.token) { TokenManager.saveToken(authData.token, true); // 构建user对象 const user = { id: authData.id, username: authData.username, phone: authData.phone, email: authData.email }; TokenManager.saveUser(user, true); } return { success: true, data: authData, message: data.message || '登录成功' }; } catch (error) { console.error('Login failed:', error); return { success: false, message: error.message || '网络错误,请稍后重试' }; } } /** * 用户注册 * @param {string} username - 用户名 * @param {string} account - 手机号或邮箱 * @param {string} verifyCode - 验证码 * @returns {Promise} API响应 */ static async register(username, account, verifyCode) { try { const response = await fetch(`${this.BASE_URL}/auth/register`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ username, // 判断是邮箱还是手机号 ...(account.includes('@') ? { email: account } : { phone: account }), code: verifyCode // 后端使用code字段 }) }); const data = await response.json(); // 后端使用code字段判断成功与否,200表示成功 if (data.code !== 200) { throw new Error(data.message || '注册失败'); } // 后端响应的数据在data字段中 const authData = data.data; if (authData && authData.token) { TokenManager.saveToken(authData.token, true); // 构建user对象 const user = { id: authData.id, username: authData.username, phone: authData.phone, email: authData.email }; TokenManager.saveUser(user, true); } return { success: true, data: authData, message: data.message || '注册成功' }; } catch (error) { console.error('Register failed:', error); return { success: false, message: error.message || '网络错误,请稍后重试' }; } } /** * 用户登出 * @returns {Promise} API响应 */ static async logout() { try { const authHeader = TokenManager.getAuthHeader(); const response = await fetch(`${this.BASE_URL}/auth/logout`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...authHeader } }); // 无论服务器响应如何,都清除本地存储 TokenManager.clearAll(); if (!response.ok) { console.warn('Server logout failed, but local data cleared'); } return { success: true, message: '退出登录成功' }; } catch (error) { console.error('Logout failed:', error); // 即使请求失败,也要清除本地数据 TokenManager.clearAll(); return { success: true, message: '已退出登录' }; } } /** * 获取用户信息 * @returns {Promise} API响应 */ static async getUserInfo() { try { const authHeader = TokenManager.getAuthHeader(); if (!authHeader) { throw new Error('未登录'); } // 从本地存储获取用户ID const localUser = TokenManager.getUser(); if (!localUser || !localUser.id) { throw new Error('用户ID不存在'); } // 使用 /api/users/{id} 接口替代 /api/users/me const response = await fetch(`${this.BASE_URL}/users/${localUser.id}`, { method: 'GET', headers: { 'Content-Type': 'application/json', ...authHeader } }); // 特殊处理403错误 if (response.status === 403) { throw new Error('403:权限配置问题'); } // 特殊处理404错误 if (response.status === 404) { throw new Error('404:接口未实现'); } // 处理401未授权 if (response.status === 401) { TokenManager.clearAll(); throw new Error('登录已过期,请重新登录'); } // 尝试解析响应 let data; try { const text = await response.text(); if (!text) { throw new Error('响应为空'); } data = JSON.parse(text); } catch (parseError) { throw new Error(`解析响应失败: ${response.status}`); } // UserController直接返回User对象,不是包装的ResponseResult // 所以这里data就是用户信息 const userData = data; // 确保不暴露密码等敏感信息 if (userData) { delete userData.password; delete userData.salt; // 更新本地存储的用户信息 TokenManager.saveUser(userData, true); } return { success: true, data: userData, message: data.message || '获取成功' }; } catch (error) { console.error('Get user info failed:', error); return { success: false, message: error.message || '网络错误,请稍后重试' }; } } /** * 刷新Token * @returns {Promise} API响应 */ static async refreshToken() { try { const refreshToken = TokenManager.getRefreshToken(); if (!refreshToken) { throw new Error('无刷新令牌'); } const response = await fetch(`${this.BASE_URL}/auth/refresh`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ refreshToken }) }); const data = await response.json(); if (!response.ok) { // 刷新失败,清除所有本地数据 TokenManager.clearAll(); throw new Error(data.error || data.message || 'Token刷新失败'); } // Spring Boot直接返回token数据 if (data.token) { TokenManager.saveToken(data.token, true); if (data.refreshToken) { TokenManager.saveRefreshToken(data.refreshToken); } } return { success: true, data: data, message: 'Token刷新成功' }; } catch (error) { console.error('Refresh token failed:', error); return { success: false, message: error.message || '刷新失败,请重新登录' }; } } /** * 检查认证状态 * @returns {Promise} 认证状态 */ static async checkAuthStatus() { try { // 先检查本地token const isTokenValid = TokenManager.isTokenValid(); const localUser = TokenManager.getUser(); if (!isTokenValid) { console.log('本地token无效,用户未登录'); return { isAuthenticated: false, user: null, message: '未登录' }; } // 如果有token,尝试从服务器获取最新用户信息 try { const userResult = await this.getUserInfo(); if (userResult.success) { console.log('成功从服务器获取用户信息:', userResult.data); return { isAuthenticated: true, user: userResult.data, message: '已登录' }; } } catch (userError) { console.warn('获取用户信息失败:', userError); // 如果API调用失败但有本地数据,使用本地数据作为降级方案 if (localUser) { console.log('API调用失败,使用本地缓存的用户信息:', localUser); return { isAuthenticated: true, user: localUser, message: '已登录(使用缓存)' }; } } return { isAuthenticated: false, user: null, message: '未登录' }; } catch (error) { console.error('Check auth status failed:', error); return { isAuthenticated: false, user: null, message: '认证检查失败' }; } } } // 导出供其他模块使用 if (typeof module !== 'undefined' && module.exports) { module.exports = AuthService; }