feat: 添加用户认证系统

引入基于 Basic Auth 的用户认证系统,包括用户管理、登录界面和 API 鉴权
- 新增用户实体和管理功能
- 实现前端登录界面和凭证管理
- 重构 API 鉴权为 Basic Auth 模式
- 添加用户管理脚本工具
This commit is contained in:
dmy
2026-01-18 12:47:16 +08:00
parent a55dfd78d2
commit b6a6398864
30 changed files with 2042 additions and 82 deletions

View File

@@ -1,5 +1,38 @@
import axios, { type InternalAxiosRequestConfig, type AxiosError } from 'axios';
/**
* 认证相关工具函数
*/
/**
* 设置 Basic Auth 凭证到 localStorage
*/
export const setAuthCredentials = (username: string, password: string) => {
const credentials = btoa(`${username}:${password}`);
localStorage.setItem('authCredentials', credentials);
};
/**
* 从 localStorage 获取 Basic Auth 凭证
*/
export const getAuthCredentials = (): string | null => {
return localStorage.getItem('authCredentials');
};
/**
* 清除认证凭证
*/
export const clearAuthCredentials = () => {
localStorage.removeItem('authCredentials');
};
/**
* 检查是否已登录
*/
export const isAuthenticated = (): boolean => {
return !!localStorage.getItem('authCredentials');
};
/**
* API配置
* 配置axios实例设置baseURL和请求拦截器
@@ -13,22 +46,10 @@ const api = axios.create({
// 请求拦截器
api.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// 如果 baseURL 不是 localhost自动添加 API Key
const baseURL =
(config.baseURL as string) ||
(api.defaults.baseURL as string) ||
'';
const isLocalhost =
baseURL.includes('localhost') || baseURL.includes('127.0.0.1');
if (!isLocalhost) {
// 从环境变量或 localStorage 获取 API Key
const apiKey =
(import.meta.env.VITE_API_KEY as string) ||
localStorage.getItem('apiKey');
if (apiKey && config.headers) {
config.headers['X-API-Key'] = apiKey;
}
// 添加 Basic Auth 头
const credentials = getAuthCredentials();
if (credentials && config.headers) {
config.headers['Authorization'] = `Basic ${credentials}`;
}
return config;
@@ -44,6 +65,13 @@ api.interceptors.response.use(
return response;
},
(error: AxiosError) => {
// 处理 401 未授权错误
if (error.response?.status === 401) {
// 清除无效的凭证
clearAuthCredentials();
// 触发自定义事件,通知应用需要重新登录
window.dispatchEvent(new CustomEvent('auth-required'));
}
console.error('API请求错误:', error);
return Promise.reject(error);
},