You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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),
}

方案二:子应用提供预校验入口模块,校验通过后动态加载主模块

针对你之前尝试的"轻量版校验应用"思路优化,通过子应用的预校验模块完成权限判断,校验通过后动态注册主模块并导航,解决应用切换问题。

子应用端实现

  1. 创建预校验模块和组件:
// 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 {}
  1. 预校验组件中实现权限判断和主模块加载:
// 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 21:12:43