refactor: 使用更简洁的方式进行认证

This commit is contained in:
2025-08-16 14:53:28 +08:00
parent c974de593a
commit e61cf96c07
24 changed files with 2118 additions and 2089 deletions

View File

@@ -1,322 +1,105 @@
import {
DataClient,
VideoStreamClient,
BsdlParserClient,
DDSClient,
JtagClient,
MatrixKeyClient,
PowerClient,
RemoteUpdateClient,
TutorialClient,
UDPClient,
LogicAnalyzerClient,
NetConfigClient,
OscilloscopeApiClient,
DebuggerClient,
ExamClient,
ResourceClient,
HdmiVideoStreamClient,
} from "@/APIClient";
import router from "@/router";
import { DataClient } from "@/APIClient";
import { HubConnectionBuilder } from "@microsoft/signalr";
import axios, { type AxiosInstance } from "axios";
import { isNull } from "lodash";
// 支持的客户端类型联合类型
type SupportedClient =
| DataClient
| VideoStreamClient
| BsdlParserClient
| DDSClient
| JtagClient
| MatrixKeyClient
| PowerClient
| RemoteUpdateClient
| TutorialClient
| LogicAnalyzerClient
| UDPClient
| NetConfigClient
| OscilloscopeApiClient
| DebuggerClient
| ExamClient
| ResourceClient
| HdmiVideoStreamClient;
// 简单到让人想哭的认证管理器
export class AuthManager {
// 存储token到localStorage
public static setToken(token: string): void {
localStorage.setItem("authToken", token);
private static readonly TOKEN_KEY = "authToken";
// 核心数据:就是个字符串
static getToken(): string | null {
return localStorage.getItem(this.TOKEN_KEY);
}
// 从localStorage获取token
public static getToken(): string | null {
return localStorage.getItem("authToken");
static setToken(token: string): void {
localStorage.setItem(this.TOKEN_KEY, token);
}
// 清除token
public static clearToken(): void {
localStorage.removeItem("authToken");
static clearToken(): void {
localStorage.removeItem(this.TOKEN_KEY);
}
// 检查是否已认证
public static async isAuthenticated(): Promise<boolean> {
return await AuthManager.verifyToken();
// 核心功能创建带认证的HTTP配置
static getAuthHeaders(): Record<string, string> {
const token = this.getToken();
return token ? { Authorization: `Bearer ${token}` } : {};
}
// 通用的为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,
// 一个方法搞定所有客户端不要17个垃圾方法
static createClient<T>(
ClientClass: new (baseUrl?: string, config?: any) => T,
baseUrl?: string,
): T {
const axiosInstance = AuthManager.createAuthenticatedAxiosInstance();
return axiosInstance
? new ClientClass(undefined, axiosInstance)
: new ClientClass();
const token = this.getToken();
if (!token) {
return new ClientClass(baseUrl);
}
// 对于axios客户端
const axiosInstance = axios.create({
headers: this.getAuthHeaders(),
});
return new ClientClass(baseUrl, axiosInstance);
}
// 便捷方法:创建已配置认证的各种客户端
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 createAuthenticatedResourceClient(): ResourceClient {
return AuthManager.createAuthenticatedClient(ResourceClient);
}
public static createAuthenticatedHdmiVideoStreamClient(): HdmiVideoStreamClient {
return AuthManager.createAuthenticatedClient(HdmiVideoStreamClient);
}
public static createAuthenticatedJtagHubConnection() {
// SignalR连接 - 简单明了
static createHubConnection(
hubPath: "ProgressHub" | "JtagHub" | "DigitalTubesHub",
) {
return new HubConnectionBuilder()
.withUrl("http://127.0.0.1:5000/hubs/JtagHub", {
.withUrl(`http://127.0.0.1:5000/hubs/${hubPath}`, {
accessTokenFactory: () => this.getToken() ?? "",
})
.withAutomaticReconnect()
.build();
}
public static createAuthenticatedProgressHubConnection() {
return new HubConnectionBuilder()
.withUrl("http://127.0.0.1:5000/hubs/ProgressHub", {
accessTokenFactory: () => this.getToken() ?? "",
})
.withAutomaticReconnect()
.build();
}
public static createAuthenticatedDigitalTubesHubConnection() {
return new HubConnectionBuilder()
.withUrl("http://127.0.0.1:5000/hubs/DigitalTubesHub", {
accessTokenFactory: () => this.getToken() ?? "",
})
.withAutomaticReconnect()
.build();
}
// 登录函数
public static async login(
username: string,
password: string,
): Promise<boolean> {
// 认证逻辑 - 去除所有废话
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);
if (!token) return false;
// 验证token
const authClient = AuthManager.createAuthenticatedDataClient();
await authClient.testAuth();
this.setToken(token);
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();
// 验证token - 如果失败直接抛异常
await this.createClient(DataClient).testAuth();
return true;
} catch (error) {
AuthManager.clearToken();
return false;
} catch {
this.clearToken();
throw new Error("Login failed");
}
}
// 验证管理员权限
public static async verifyAdminAuth(): Promise<boolean> {
static logout(): void {
this.clearToken();
}
// 简单的验证 - 不要搞复杂
static async isAuthenticated(): Promise<boolean> {
if (!this.getToken()) return false;
try {
const token = AuthManager.getToken();
if (!token) {
return false;
}
const client = AuthManager.createAuthenticatedDataClient();
await client.testAdminAuth();
await this.createClient(DataClient).testAuth();
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);
}
} catch {
this.clearToken();
return false;
}
}
// 检查客户端是否已配置认证
public static isClientAuthenticated(client: SupportedClient): boolean {
const token = AuthManager.getToken();
return !!token;
static async isAdminAuthenticated(): Promise<boolean> {
if (!this.getToken()) return false;
try {
await this.createClient(DataClient).testAdminAuth();
return true;
} catch {
this.clearToken();
return false;
}
}
}

View File

@@ -17,7 +17,7 @@ export interface BoardData extends Board {
const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
// 远程升级相关参数
const devPort = 1234;
const remoteUpdater = AuthManager.createAuthenticatedRemoteUpdateClient();
const remoteUpdater = AuthManager.createClient(RemoteUpdateClient);
// 统一的板卡数据
const boards = ref<BoardData[]>([]);
@@ -35,13 +35,13 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
async function getAllBoards(): Promise<{ success: boolean; error?: string }> {
try {
// 验证管理员权限
const hasAdminAuth = await AuthManager.verifyAdminAuth();
const hasAdminAuth = await AuthManager.isAdminAuthenticated();
if (!hasAdminAuth) {
console.error("权限验证失败");
return { success: false, error: "权限不足" };
}
const client = AuthManager.createAuthenticatedDataClient();
const client = AuthManager.createClient(DataClient);
const result = await client.getAllBoards();
if (result) {
@@ -77,7 +77,7 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
): Promise<{ success: boolean; error?: string; boardId?: string }> {
try {
// 验证管理员权限
const hasAdminAuth = await AuthManager.verifyAdminAuth();
const hasAdminAuth = await AuthManager.isAdminAuthenticated();
if (!hasAdminAuth) {
console.error("权限验证失败");
return { success: false, error: "权限不足" };
@@ -89,11 +89,11 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
return { success: false, error: "参数不完整" };
}
const client = AuthManager.createAuthenticatedDataClient();
const client = AuthManager.createClient(DataClient);
const boardId = await client.addBoard(name);
if (boardId) {
console.log("新增板卡成功", { boardId, name});
console.log("新增板卡成功", { boardId, name });
// 刷新板卡列表
await getAllBoards();
return { success: true };
@@ -119,7 +119,7 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
): Promise<{ success: boolean; error?: string }> {
try {
// 验证管理员权限
const hasAdminAuth = await AuthManager.verifyAdminAuth();
const hasAdminAuth = await AuthManager.isAdminAuthenticated();
if (!hasAdminAuth) {
console.error("权限验证失败");
return { success: false, error: "权限不足" };
@@ -130,7 +130,7 @@ const [useProvideBoardManager, useBoardManager] = createInjectionState(() => {
return { success: false, error: "板卡ID不能为空" };
}
const client = AuthManager.createAuthenticatedDataClient();
const client = AuthManager.createClient(DataClient);
const result = await client.deleteBoard(boardId);
if (result > 0) {