如何在Angular Monorepo懒加载应用中实现非父应用托管的用户访问控制
解决方案:Angular Monorepo中子应用自主权限校验
方案一:子应用导出权限校验函数,父应用路由用canLoad触发调用
核心思路是让子应用封装权限校验逻辑并导出,父应用仅在路由的canLoad守卫中导入并调用该函数,权限判断逻辑完全保留在子应用内部,父应用不参与任何权限决策。
子应用端实现
在子应用中创建权限校验文件,封装专属校验逻辑:
// projects/project1/src/app/auth-checker.ts export const checkProject1Access = async (): Promise<boolean> => { // 这里是子应用专属的权限校验逻辑,比如调用后端接口、读取用户权限缓存等 const response = await fetch('/api/project1/validate-user-permission'); return response.ok && await response.json(); };
父应用路由配置
在父应用的路由配置中,通过canLoad导入子应用的校验函数,只有校验通过才会加载子应用主模块:
{ path: 'project1', // 先调用子应用的权限校验函数,通过后才加载主模块 canLoad: [() => import('../../projects/project1/src/app/auth-checker').then(m => m.checkProject1Access())], loadChildren: () => import('../../projects/project1/src/app/app.module').then(m => m.AppModule), }
方案二:子应用提供预校验入口模块,校验通过后动态加载主模块
针对你之前尝试的"轻量版校验应用"思路优化,通过子应用的预校验模块完成权限判断,校验通过后动态注册主模块并导航,解决应用切换问题。
子应用端实现
- 创建预校验模块和组件:
// projects/project1/src/app/auth-preload.module.ts import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AuthPreloadComponent } from './auth-preload.component'; const routes: Routes = [{ path: '', component: AuthPreloadComponent }]; @NgModule({ imports: [RouterModule.forChild(routes)], declarations: [AuthPreloadComponent] }) export class AuthPreloadModule {}
- 预校验组件中实现权限判断和主模块加载:
// projects/project1/src/app/auth-preload.component.ts import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { AuthService } from './auth.service'; @Component({ template: '' // 空模板,仅做权限校验逻辑 }) export class AuthPreloadComponent implements OnInit { constructor(private authService: AuthService, private router: Router) {} async ngOnInit() { const hasAccess = await this.authService.validateUserAccess(); if (hasAccess) { // 校验通过,动态加载子应用主模块并更新路由配置 const { AppModule } = await import('./app.module'); // 将主模块路由添加到路由配置最前面,确保优先匹配 this.router.config.unshift({ path: 'project1', loadChildren: () => Promise.resolve(AppModule) }); // 重新导航到当前路径,触发主模块加载 this.router.navigate(['/project1']); } else { // 无权限时跳转到父应用的无权限页面 this.router.navigate(['/access-denied']); } } }
父应用路由配置
父应用路由直接指向子应用的预校验模块:
{ path: 'project1', loadChildren: () => import('../../projects/project1/src/app/auth-preload.module').then(m => m.AuthPreloadModule), }
方案三:通用子应用权限守卫(多子应用场景)
如果有多个子应用,可以封装一个通用守卫,根据路由路径动态加载对应子应用的校验逻辑,避免重复代码。
父应用端通用守卫
// app/guards/child-app-auth.guard.ts import { CanLoad, Route, Router } from '@angular/router'; import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root' }) export class ChildAppAuthGuard implements CanLoad { constructor(private router: Router) {} async canLoad(route: Route): Promise<boolean> { const childAppPath = route.path; let checkAccess: () => Promise<boolean>; // 根据子应用路径匹配对应的校验函数 switch (childAppPath) { case 'project1': checkAccess = (await import('../../projects/project1/src/app/auth-checker')).checkProject1Access; break; case 'project2': checkAccess = (await import('../../projects/project2/src/app/auth-checker')).checkProject2Access; break; default: return false; } const hasAccess = await checkAccess(); if (!hasAccess) { this.router.navigate(['/access-denied']); return false; } return true; } }
父应用路由配置
所有子应用路由复用同一个守卫:
{ path: 'project1', canLoad: [ChildAppAuthGuard], loadChildren: () => import('../../projects/project1/src/app/app.module').then(m => m.AppModule), }, { path: 'project2', canLoad: [ChildAppAuthGuard], loadChildren: () => import('../../projects/project2/src/app/app.module').then(m => m.AppModule), }
内容的提问来源于stack exchange,提问作者manish
相关产品推荐
相关产品推荐

