281 lines
8.1 KiB
TypeScript
281 lines
8.1 KiB
TypeScript
import {
|
||
DataClient,
|
||
VideoStreamClient,
|
||
BsdlParserClient,
|
||
DDSClient,
|
||
JtagClient,
|
||
MatrixKeyClient,
|
||
PowerClient,
|
||
RemoteUpdateClient,
|
||
TutorialClient,
|
||
UDPClient,
|
||
LogicAnalyzerClient,
|
||
NetConfigClient,
|
||
OscilloscopeApiClient,
|
||
DebuggerClient,
|
||
ExamClient,
|
||
} from "@/APIClient";
|
||
import axios, { type AxiosInstance } from "axios";
|
||
|
||
// 支持的客户端类型联合类型
|
||
type SupportedClient =
|
||
| DataClient
|
||
| VideoStreamClient
|
||
| BsdlParserClient
|
||
| DDSClient
|
||
| JtagClient
|
||
| MatrixKeyClient
|
||
| PowerClient
|
||
| RemoteUpdateClient
|
||
| TutorialClient
|
||
| LogicAnalyzerClient
|
||
| UDPClient
|
||
| NetConfigClient
|
||
| OscilloscopeApiClient
|
||
| DebuggerClient
|
||
| ExamClient;
|
||
|
||
export class AuthManager {
|
||
// 存储token到localStorage
|
||
public static setToken(token: string): void {
|
||
localStorage.setItem("authToken", token);
|
||
}
|
||
|
||
// 从localStorage获取token
|
||
public static getToken(): string | null {
|
||
return localStorage.getItem("authToken");
|
||
}
|
||
|
||
// 清除token
|
||
public static clearToken(): void {
|
||
localStorage.removeItem("authToken");
|
||
}
|
||
|
||
// 检查是否已认证
|
||
public static async isAuthenticated(): Promise<boolean> {
|
||
return await AuthManager.verifyToken();
|
||
}
|
||
|
||
// 通用的为HTTP请求添加Authorization header的方法
|
||
public static addAuthHeader(client: SupportedClient): void {
|
||
const token = AuthManager.getToken();
|
||
if (token) {
|
||
// 创建一个自定义的 http 对象,包装原有的 fetch 方法
|
||
const customHttp = {
|
||
fetch: (url: RequestInfo, init?: RequestInit) => {
|
||
if (!init) init = {};
|
||
if (!init.headers) init.headers = {};
|
||
|
||
// 添加Authorization header
|
||
if (typeof init.headers === "object" && init.headers !== null) {
|
||
(init.headers as any)["Authorization"] = `Bearer ${token}`;
|
||
}
|
||
|
||
// 使用全局 fetch 或 window.fetch
|
||
return (window as any).fetch(url, init);
|
||
},
|
||
};
|
||
|
||
// 重新构造客户端,传入自定义的 http 对象
|
||
const ClientClass = client.constructor as new (
|
||
baseUrl?: string,
|
||
http?: any,
|
||
) => SupportedClient;
|
||
const newClient = new ClientClass(undefined, customHttp);
|
||
|
||
// 将新客户端的属性复制到原客户端(这是一个 workaround)
|
||
// 更好的做法是返回新的客户端实例
|
||
Object.setPrototypeOf(client, Object.getPrototypeOf(newClient));
|
||
Object.assign(client, newClient);
|
||
}
|
||
}
|
||
|
||
// 私有方法:创建带认证的HTTP客户端
|
||
private static createAuthenticatedHttp() {
|
||
const token = AuthManager.getToken();
|
||
if (!token) {
|
||
return null;
|
||
}
|
||
|
||
return {
|
||
fetch: (url: RequestInfo, init?: RequestInit) => {
|
||
if (!init) init = {};
|
||
if (!init.headers) init.headers = {};
|
||
|
||
if (typeof init.headers === "object" && init.headers !== null) {
|
||
(init.headers as any)["Authorization"] = `Bearer ${token}`;
|
||
}
|
||
|
||
return (window as any).fetch(url, init);
|
||
},
|
||
};
|
||
}
|
||
|
||
// 私有方法:创建带认证的Axios实例
|
||
private static createAuthenticatedAxiosInstance(): AxiosInstance | null {
|
||
const token = AuthManager.getToken();
|
||
if (!token) return null;
|
||
|
||
const instance = axios.create();
|
||
instance.interceptors.request.use(config => {
|
||
config.headers = config.headers || {};
|
||
(config.headers as any)["Authorization"] = `Bearer ${token}`;
|
||
return config;
|
||
});
|
||
return instance;
|
||
}
|
||
|
||
// 通用的创建已认证客户端的方法(使用泛型)
|
||
public static createAuthenticatedClient<T extends SupportedClient>(
|
||
ClientClass: new (baseUrl?: string, instance?: AxiosInstance) => T,
|
||
): T {
|
||
const axiosInstance = AuthManager.createAuthenticatedAxiosInstance();
|
||
return axiosInstance
|
||
? new ClientClass(undefined, axiosInstance)
|
||
: new ClientClass();
|
||
}
|
||
|
||
// 便捷方法:创建已配置认证的各种客户端
|
||
public static createAuthenticatedDataClient(): DataClient {
|
||
return AuthManager.createAuthenticatedClient(DataClient);
|
||
}
|
||
|
||
public static createAuthenticatedVideoStreamClient(): VideoStreamClient {
|
||
return AuthManager.createAuthenticatedClient(VideoStreamClient);
|
||
}
|
||
|
||
public static createAuthenticatedBsdlParserClient(): BsdlParserClient {
|
||
return AuthManager.createAuthenticatedClient(BsdlParserClient);
|
||
}
|
||
|
||
public static createAuthenticatedDDSClient(): DDSClient {
|
||
return AuthManager.createAuthenticatedClient(DDSClient);
|
||
}
|
||
|
||
public static createAuthenticatedJtagClient(): JtagClient {
|
||
return AuthManager.createAuthenticatedClient(JtagClient);
|
||
}
|
||
|
||
public static createAuthenticatedMatrixKeyClient(): MatrixKeyClient {
|
||
return AuthManager.createAuthenticatedClient(MatrixKeyClient);
|
||
}
|
||
|
||
public static createAuthenticatedPowerClient(): PowerClient {
|
||
return AuthManager.createAuthenticatedClient(PowerClient);
|
||
}
|
||
|
||
public static createAuthenticatedRemoteUpdateClient(): RemoteUpdateClient {
|
||
return AuthManager.createAuthenticatedClient(RemoteUpdateClient);
|
||
}
|
||
|
||
public static createAuthenticatedTutorialClient(): TutorialClient {
|
||
return AuthManager.createAuthenticatedClient(TutorialClient);
|
||
}
|
||
|
||
public static createAuthenticatedUDPClient(): UDPClient {
|
||
return AuthManager.createAuthenticatedClient(UDPClient);
|
||
}
|
||
|
||
public static createAuthenticatedLogicAnalyzerClient(): LogicAnalyzerClient {
|
||
return AuthManager.createAuthenticatedClient(LogicAnalyzerClient);
|
||
}
|
||
|
||
public static createAuthenticatedNetConfigClient(): NetConfigClient {
|
||
return AuthManager.createAuthenticatedClient(NetConfigClient);
|
||
}
|
||
|
||
public static createAuthenticatedOscilloscopeApiClient(): OscilloscopeApiClient {
|
||
return AuthManager.createAuthenticatedClient(OscilloscopeApiClient);
|
||
}
|
||
|
||
public static createAuthenticatedDebuggerClient(): DebuggerClient {
|
||
return AuthManager.createAuthenticatedClient(DebuggerClient);
|
||
}
|
||
|
||
public static createAuthenticatedExamClient(): ExamClient {
|
||
return AuthManager.createAuthenticatedClient(ExamClient);
|
||
}
|
||
|
||
// 登录函数
|
||
public static async login(
|
||
username: string,
|
||
password: string,
|
||
): Promise<boolean> {
|
||
try {
|
||
const client = new DataClient();
|
||
const token = await client.login(username, password);
|
||
|
||
if (token) {
|
||
AuthManager.setToken(token);
|
||
|
||
// 验证token
|
||
const authClient = AuthManager.createAuthenticatedDataClient();
|
||
await authClient.testAuth();
|
||
|
||
return true;
|
||
}
|
||
return false;
|
||
} catch (error) {
|
||
AuthManager.clearToken();
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
// 登出函数
|
||
public static logout(): void {
|
||
AuthManager.clearToken();
|
||
}
|
||
|
||
// 验证当前token是否有效
|
||
public static async verifyToken(): Promise<boolean> {
|
||
try {
|
||
const token = AuthManager.getToken();
|
||
if (!token) {
|
||
return false;
|
||
}
|
||
|
||
const client = AuthManager.createAuthenticatedDataClient();
|
||
await client.testAuth();
|
||
return true;
|
||
} catch (error) {
|
||
AuthManager.clearToken();
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 验证管理员权限
|
||
public static async verifyAdminAuth(): Promise<boolean> {
|
||
try {
|
||
const token = AuthManager.getToken();
|
||
if (!token) {
|
||
return false;
|
||
}
|
||
|
||
const client = AuthManager.createAuthenticatedDataClient();
|
||
await client.testAdminAuth();
|
||
return true;
|
||
} catch (error) {
|
||
// 只有在token完全无效的情况下才清除token
|
||
// 401错误表示token有效但权限不足,不应清除token
|
||
if (error && typeof error === "object" && "status" in error) {
|
||
// 如果是403 (Forbidden) 或401 (Unauthorized),说明token有效但权限不足
|
||
if (error.status === 401 || error.status === 403) {
|
||
return false;
|
||
}
|
||
// 其他状态码可能表示token无效,清除token
|
||
AuthManager.clearToken();
|
||
} else {
|
||
// 网络错误等,不清除token
|
||
console.error("管理员权限验证失败:", error);
|
||
}
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 检查客户端是否已配置认证
|
||
public static isClientAuthenticated(client: SupportedClient): boolean {
|
||
const token = AuthManager.getToken();
|
||
return !!token;
|
||
}
|
||
}
|