Files
AIEC-new/AIEC-server/services/api/auth-service.js
2025-10-17 09:31:28 +08:00

395 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 认证服务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;
}