FPGA_WebLab/src/utils/AuthManager.ts

281 lines
8.1 KiB
TypeScript
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.

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;
}
}