/**
* @file 常用路由守卫
* @description 提供常用的路由守卫实现
* @author JunBin.Yang
*/
import { RouteGuard, RouteContext, GuardResult } from './RouteGuard';
/**
* 登录守卫配置
*/
export interface AuthGuardConfig {
/**
* 守卫名称
*/
name?: string;
/**
* 需要登录的路由列表
*/
protectedRoutes: string[];
/**
* 登录页路由
*/
loginRoute: string;
/**
* 检查是否已登录的函数
*/
isAuthenticated: () => boolean | Promise<boolean>;
/**
* 登录拦截时的回调
*/
onAuthRequired?: (context: RouteContext) => void;
}
/**
* 实现登录守卫
*/
class AuthGuard implements RouteGuard {
name?: string;
priority: number = 10;
private protectedSet: Set<string>;
private config: AuthGuardConfig;
constructor(config: AuthGuardConfig) {
this.config = config;
this.name = config.name ?? 'AuthGuard';
this.protectedSet = new Set(config.protectedRoutes);
}
async canActivate(context: RouteContext): Promise<GuardResult> {
if (!this.protectedSet.has(context.targetRoute)) {
return { canActivate: true };
}
const isLoggedIn = await this.config.isAuthenticated();
if (isLoggedIn) {
return { canActivate: true };
}
return {
canActivate: false,
redirectTo: this.config.loginRoute,
reason: 'Authentication required'
};
}
onReject(context: RouteContext, _result: GuardResult): void {
this.config.onAuthRequired?.(context);
}
}
/**
* 创建登录守卫
* @param config 守卫配置
* @returns 路由守卫实例
*/
export function createAuthGuard(config: AuthGuardConfig): RouteGuard {
return new AuthGuard(config);
}
/**
* 权限守卫配置
*/
export interface PermissionGuardConfig {
/**
* 守卫名称
*/
name?: string;
/**
* 路由权限映射
*/
routePermissions: Map<string, string[]>;
/**
* 获取用户权限的函数
*/
getUserPermissions: () => string[] | Promise<string[]>;
/**
* 无权限时的重定向路由
*/
forbiddenRoute?: string;
/**
* 无权限时的回调
*/
onForbidden?: (context: RouteContext, requiredPermissions: string[]) => void;
}
/**
* 实现权限守卫
*/
class PermissionGuard implements RouteGuard {
name?: string;
priority: number = 20;
private config: PermissionGuardConfig;
constructor(config: PermissionGuardConfig) {
this.config = config;
this.name = config.name ?? 'PermissionGuard';
}
async canActivate(context: RouteContext): Promise<GuardResult> {
const requiredPermissions = this.config.routePermissions.get(context.targetRoute);
if (!requiredPermissions || requiredPermissions.length === 0) {
return { canActivate: true };
}
const userPermissions = await this.config.getUserPermissions();
const userSet = new Set(userPermissions);
const hasAll = requiredPermissions.every(p => userSet.has(p));
if (hasAll) {
return { canActivate: true };
}
return {
canActivate: false,
redirectTo: this.config.forbiddenRoute,
reason: `Missing permissions: ${requiredPermissions.filter(p => !userSet.has(p)).join(', ')}`
};
}
onReject(context: RouteContext, _result: GuardResult): void {
if (this.config.onForbidden) {
const perms = this.config.routePermissions.get(context.targetRoute) ?? [];
this.config.onForbidden(context, perms);
}
}
}
/**
* 创建权限守卫
* @param config 守卫配置
* @returns 路由守卫实例
*/
export function createPermissionGuard(config: PermissionGuardConfig): RouteGuard {
return new PermissionGuard(config);
}
/**
* 条件守卫配置
*/
export interface ConditionalGuardConfig {
/**
* 守卫名称
*/
name?: string;
/**
* 优先级
*/
priority?: number;
/**
* 条件检查函数
*/
condition: (context: RouteContext) => boolean | Promise<boolean>;
/**
* 条件不满足时的重定向路由
*/
redirectTo?: string;
/**
* 条件不满足时的回调
*/
onConditionFailed?: (context: RouteContext) => void;
}
/**
* 实现条件守卫
*/
class ConditionalGuard implements RouteGuard {
name: string;
priority: number;
private config: ConditionalGuardConfig;
constructor(config: ConditionalGuardConfig) {
this.config = config;
this.name = config.name ?? 'ConditionalGuard';
this.priority = config.priority ?? 50;
}
async canActivate(context: RouteContext): Promise<GuardResult> {
const passed = await this.config.condition(context);
if (passed) {
return { canActivate: true };
}
return {
canActivate: false,
redirectTo: this.config.redirectTo
};
}
onReject(context: RouteContext, _result: GuardResult): void {
this.config.onConditionFailed?.(context);
}
}
/**
* 创建条件守卫
* @param config 守卫配置
* @returns 路由守卫实例
*/
export function createConditionalGuard(config: ConditionalGuardConfig): RouteGuard {
return new ConditionalGuard(config);
}
/**
* 日志守卫(用于调试)
* 记录所有导航事件
*/
class LogGuard implements RouteGuard {
name: string;
priority: number = 1;
constructor(name: string = 'LogGuard') {
this.name = name;
}
canActivate(context: RouteContext): GuardResult {
console.log(`[${this.name}] Navigation: ${context.fromRoute ?? 'root'} -> ${context.targetRoute}`);
if (context.params) {
console.log(`[${this.name}] Params: ${JSON.stringify(context.params)}`);
}
return { canActivate: true };
}
}
export function createLogGuard(name: string = 'LogGuard'): RouteGuard {
return new LogGuard(name);
}