AIClient-2-API/static/app/auth.js
hex2077 ee050c77f2 feat: 新增Web UI管理控制台和认证系统
新增Web UI管理控制台,支持实时配置管理和健康状态监控
添加登录认证系统,包含token生成和验证机制
实现供应商池的启用/禁用功能
更新README文档,添加安装脚本和Web UI使用说明
优化配置文件管理界面,增加API客户端封装
新增登录页面和认证中间件
2025-11-12 17:37:39 +08:00

305 lines
No EOL
7.7 KiB
JavaScript
Raw 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.

// 认证模块 - 处理token管理和API调用封装
/**
* 认证管理类
*/
class AuthManager {
constructor() {
this.tokenKey = 'authToken';
this.expiryKey = 'authTokenExpiry';
this.baseURL = window.location.origin;
}
/**
* 获取存储的token
*/
getToken() {
return localStorage.getItem(this.tokenKey);
}
/**
* 获取token过期时间
*/
getTokenExpiry() {
const expiry = localStorage.getItem(this.expiryKey);
return expiry ? parseInt(expiry) : null;
}
/**
* 检查token是否有效
*/
isTokenValid() {
const token = this.getToken();
const expiry = this.getTokenExpiry();
if (!token) return false;
// 如果设置了过期时间,检查是否过期
if (expiry && Date.now() > expiry) {
this.clearToken();
return false;
}
return true;
}
/**
* 保存token到本地存储
*/
saveToken(token, rememberMe = false) {
localStorage.setItem(this.tokenKey, token);
if (rememberMe) {
const expiryTime = Date.now() + (7 * 24 * 60 * 60 * 1000); // 7天
localStorage.setItem(this.expiryKey, expiryTime.toString());
}
}
/**
* 清除token
*/
clearToken() {
localStorage.removeItem(this.tokenKey);
localStorage.removeItem(this.expiryKey);
}
/**
* 登出
*/
async logout() {
this.clearToken();
window.location.href = '/login.html';
}
}
/**
* API调用封装类
*/
class ApiClient {
constructor() {
this.authManager = new AuthManager();
this.baseURL = window.location.origin;
}
/**
* 获取带认证的请求头
*/
getAuthHeaders() {
const token = this.authManager.getToken();
return token ? {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
} : {
'Content-Type': 'application/json'
};
}
/**
* 处理401错误重定向到登录页
*/
handleUnauthorized() {
this.authManager.clearToken();
window.location.href = '/login.html';
}
/**
* 通用API请求方法
*/
async request(endpoint, options = {}) {
const url = `${this.baseURL}/api${endpoint}`;
const headers = {
...this.getAuthHeaders(),
...options.headers
};
const config = {
...options,
headers
};
try {
const response = await fetch(url, config);
// 如果是401错误重定向到登录页
if (response.status === 401) {
this.handleUnauthorized();
throw new Error('未授权访问');
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
} else {
return await response.text();
}
} catch (error) {
if (error.message === '未授权访问') {
// 已经在handleUnauthorized中处理了重定向
throw error;
}
console.error('API请求错误:', error);
throw error;
}
}
/**
* GET请求
*/
async get(endpoint, params = {}) {
const queryString = new URLSearchParams(params).toString();
const url = queryString ? `${endpoint}?${queryString}` : endpoint;
return this.request(url, { method: 'GET' });
}
/**
* POST请求
*/
async post(endpoint, data = {}) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(data)
});
}
/**
* PUT请求
*/
async put(endpoint, data = {}) {
return this.request(endpoint, {
method: 'PUT',
body: JSON.stringify(data)
});
}
/**
* DELETE请求
*/
async delete(endpoint) {
return this.request(endpoint, { method: 'DELETE' });
}
/**
* POST请求支持FormData上传
*/
async upload(endpoint, formData) {
const url = `${this.baseURL}/api${endpoint}`;
// 获取认证token
const token = this.authManager.getToken();
const headers = {};
// 如果有token添加Authorization头部
if (token) {
headers['Authorization'] = `Bearer ${token}`;
}
// 对于FormData请求不添加Content-Type头部让浏览器自动设置
const config = {
method: 'POST',
headers,
body: formData
};
try {
const response = await fetch(url, config);
// 如果是401错误重定向到登录页
if (response.status === 401) {
this.handleUnauthorized();
throw new Error('未授权访问');
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
} else {
return await response.text();
}
} catch (error) {
if (error.message === '未授权访问') {
// 已经在handleUnauthorized中处理了重定向
throw error;
}
console.error('API请求错误:', error);
throw error;
}
}
}
/**
* 初始化认证检查
*/
async function initAuth() {
const authManager = new AuthManager();
// 检查是否已经有有效的token
if (authManager.isTokenValid()) {
// 验证token是否仍然有效发送一个测试请求
try {
const apiClient = new ApiClient();
await apiClient.get('/health');
return true;
} catch (error) {
// Token无效清除并重定向到登录页
authManager.clearToken();
window.location.href = '/login.html';
return false;
}
} else {
// 没有有效token重定向到登录页
window.location.href = '/login.html';
return false;
}
}
/**
* 登出函数
*/
async function logout() {
const authManager = new AuthManager();
await authManager.logout();
}
/**
* 登录函数(供登录页面使用)
*/
async function login(password, rememberMe = false) {
try {
const response = await fetch('/api/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
password,
rememberMe
})
});
const data = await response.json();
if (data.success) {
// 保存token
const authManager = new AuthManager();
authManager.saveToken(data.token, rememberMe);
return { success: true };
} else {
return { success: false, message: data.message };
}
} catch (error) {
console.error('登录错误:', error);
return { success: false, message: '登录失败,请检查网络连接' };
}
}
// 导出实例
window.authManager = new AuthManager();
window.apiClient = new ApiClient();
window.initAuth = initAuth;
window.logout = logout;
window.login = login;
// 导出认证管理器类和API客户端类供其他模块使用
window.AuthManager = AuthManager;
window.ApiClient = ApiClient;
console.log('认证模块已加载');