/**
* @file 路由守卫管理器
* @description 管理路由守卫的注册、执行和生命周期
* @author JunBin.Yang
*/
import { RouteGuard, RouteContext, GuardResult, GuardConfig } from './RouteGuard';
import { Logger } from '@core/util';
const TAG: string = 'GuardManager';
/**
* 路由守卫管理器
* 负责管理所有路由守卫的注册和执行
*/
export class GuardManager {
/**
* 已注册的守卫列表
*/
private guards: RouteGuard[] = [];
/**
* 是否启用日志
*/
private enableLog: boolean = true;
/**
* 构造函数
* @param enableLog 是否启用日志
*/
constructor(enableLog: boolean = true) {
this.enableLog = enableLog;
}
/**
* 注册路由守卫
* @param guard 守卫实例
*/
register(guard: RouteGuard): void {
// 按优先级排序插入
const priority = guard.priority ?? 100;
let insertIndex = this.guards.findIndex(g => (g.priority ?? 100) > priority);
if (insertIndex === -1) {
insertIndex = this.guards.length;
}
this.guards.splice(insertIndex, 0, guard);
this.log(`Guard registered: ${guard.name ?? 'unnamed'}, priority: ${priority}`);
}
/**
* 注销路由守卫
* @param guard 守卫实例
* @returns 是否注销成功
*/
unregister(guard: RouteGuard): boolean {
const index = this.guards.indexOf(guard);
if (index !== -1) {
this.guards.splice(index, 1);
this.log(`Guard unregistered: ${guard.name ?? 'unnamed'}`);
return true;
}
return false;
}
/**
* 通过名称注销守卫
* @param name 守卫名称
* @returns 是否注销成功
*/
unregisterByName(name: string): boolean {
const index = this.guards.findIndex(g => g.name === name);
if (index !== -1) {
this.guards.splice(index, 1);
this.log(`Guard unregistered by name: ${name}`);
return true;
}
return false;
}
/**
* 执行所有守卫
* @param context 路由上下文
* @returns 守卫执行结果
*/
async runGuards(context: RouteContext): Promise<GuardResult> {
this.log(`Running guards for route: ${context.targetRoute}`);
for (const guard of this.guards) {
try {
const result = await this.executeGuard(guard, context);
if (!result.canActivate) {
this.log(`Guard "${guard.name ?? 'unnamed'}" rejected navigation to ${context.targetRoute}`);
// 调用拒绝回调
if (guard.onReject) {
guard.onReject(context, result);
}
return result;
}
} catch (error) {
this.logError(`Guard "${guard.name ?? 'unnamed'}" threw error: ${error}`);
return {
canActivate: false,
reason: `Guard error: ${error}`
};
}
}
this.log(`All guards passed for route: ${context.targetRoute}`);
return { canActivate: true };
}
/**
* 执行单个守卫
* @param guard 守卫实例
* @param context 路由上下文
* @returns 守卫结果
*/
private async executeGuard(guard: RouteGuard, context: RouteContext): Promise<GuardResult> {
const result = await guard.canActivate(context);
if (typeof result === 'boolean') {
return { canActivate: result };
}
return result;
}
/**
* 清空所有守卫
*/
clear(): void {
this.guards = [];
this.log('All guards cleared');
}
/**
* 获取已注册的守卫数量
* @returns 守卫数量
*/
get size(): number {
return this.guards.length;
}
/**
* 获取所有守卫名称
* @returns 守卫名称列表
*/
getGuardNames(): string[] {
return this.guards.map(g => g.name ?? 'unnamed');
}
/**
* 设置是否启用日志
* @param enable 是否启用
*/
setLogEnabled(enable: boolean): void {
this.enableLog = enable;
}
/**
* 记录日志
*/
private log(message: string): void {
if (this.enableLog) {
Logger.info(message, TAG);
}
}
/**
* 记录错误日志
*/
private logError(message: string): void {
Logger.error(message, TAG);
}
}
/**
* 通用守卫类
*/
class GenericGuard implements RouteGuard {
name?: string;
priority: number;
private config: GuardConfig;
constructor(config: GuardConfig) {
this.config = config;
this.name = config.name;
this.priority = config.priority ?? 100; // 默认优先级与接口一致
}
async canActivate(context: RouteContext): Promise<GuardResult> {
// 如果指定了路由列表,且当前路由不在其中,则跳过校验(放行)
if (this.config.routes && this.config.routes.length > 0) {
if (!this.config.routes.includes(context.targetRoute)) {
return { canActivate: true };
}
}
// 执行自定义校验逻辑
const passed = await this.config.check();
if (passed) {
return { canActivate: true };
}
return {
canActivate: false,
redirectTo: this.config.redirectTo
};
}
onReject(context: RouteContext, _result: GuardResult): void {
if (this.config.onFail) {
this.config.onFail(context);
}
}
}
/**
* 从配置创建守卫
* @param config 守卫配置
* @returns 路由守卫实例
*/
export function createGuard(config: GuardConfig): RouteGuard {
return new GenericGuard(config);
}