Angular CanLoad 防护仅在第一次延迟加载时触发一次?

Posted

技术标签:

【中文标题】Angular CanLoad 防护仅在第一次延迟加载时触发一次?【英文标题】:Angular CanLoad guard triggers only once upon first lazy load? 【发布时间】:2020-01-02 13:49:29 【问题描述】:

我遇到了一种奇怪的行为(或者可能是通缉行为)。我有一个 Angular 应用程序,其中所有模块都是延迟加载的。

在一个模块上,我有一个警卫来检查来自 JWT 的解码用户是否是 系统管理员。如果是这样,用户应继续该部分,否则它将在仪表板中重定向。

奇怪的是,这个东西第一次模块加载时起作用。然后,如果我尝试以 not 作为系统管理员的用户注销并访问,CanLoad 防护不会触发。

我还尝试在同一个保护中实现(CanActivate 和 CanActivateChild)接口,并将保护分别放在 app-routing.module.tsfeature-routing.module.ts 模块上,分别在 CanLoadCanActivateCanActivateChild 属性。

CanActivate CanActivateChild 方法从不 被调用。 从不

而放在app-routing.module.ts 上的CanLoad 只被调用一次。

这是is-sys-adm.guard.ts 文件:

export class SFWIsSysAdmGuard implements CanLoad, CanActivate, CanActivateChild 

        public constructor(
            private readonly accessSvc: SFWAuthService,
            private readonly toastSvc: NbToastrService,
            private readonly translateSvc: TranslateService,
            private readonly navigationSvc: NavigationService,
        )  


        public canActivateChild(childRoute: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean 
            console.log('Can activate child hit');
            return this.canLoad(undefined, undefined);
        

        public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean 
            console.log('Can activate hit');
            return this.canLoad(undefined, undefined);
        

        public canLoad(route: Route, segments: UrlSegment[]): boolean 
            console.log('Can load hit');
            const decodedUser = this.accessSvc.decodedUser;
            if (!!decodedUser && !!decodedUser.isSystemAdmin) 
                return true;
            

            this.navigationSvc.goToDashboard();
            this.toastSvc.warning(
                this.translateSvc.instant('framework.guards.adm_only.access_denied'),
                this.translateSvc.instant('common.access_to_section_denied_ttl'),
            );
            return false;
        
    

这是app-routing.module.ts 文件:

const routes: Routes = [
        
            path: '',
            redirectTo: `/$AppRoutes.access`,
            pathMatch: 'full'
        ,
        
            path: AppRoutes.dashboard,
            loadChildren: () => import('./dashboard/dashboard.module').then(mod => mod.DashboardModule)
        ,
        
            path: AppRoutes.pins,
            loadChildren: () => import('./pins/pins.module').then(mod => mod.PinsModule)
        ,
        
            path: AppRoutes.pinTypes,
            loadChildren: () => import('./pin-types/pin-types.module').then(mod => mod.PinTypesModule)
        ,
        
            path: AppRoutes.organizationPickup,
            loadChildren: () => import('./organization-picker/organization-picker.module').then(mod => mod.OrganizationPickerModule)
        ,
        
            path: AppRoutes.access,
            loadChildren: () => import('./access/access.module').then(mod => mod.AccessModule)
        ,
        
            path: AppRoutes.tourism,
            loadChildren: () => import('./tourism/tourism.module').then(mod => mod.TourismModule)
        ,
        
            path: AppRoutes.security,
            canLoad: [SFWIsSysAdmGuard],
            loadChildren: () => import('./security/security.module').then(mod => mod.SecurityModule)
        ,
        
            path: AppRoutes.notFound,
            loadChildren: () => import('./not-found/not-found.module').then(mod => mod.NotFoundModule)
        ,
        
            path: '**',
            redirectTo: '/404'
        
    ];

@NgModule(
    imports: [RouterModule.forRoot(routes)],
    exports: [RouterModule]
)
export class AppRoutingModule  

最后但同样重要的是:feature-routing.module.ts 文件:

const routes: Routes = [
    
        path: '',
        canActivate: [SFWIsSysAdmGuard],
        component: SecurityComponent,
        children: [
            
                path: 'tokens-generator',
                canActivateChild: [SFWIsSysAdmGuard],
                component: TokensGeneratorComponent
            ,
        ]
    
];

@NgModule(
    imports: [RouterModule.forChild(routes)],
    exports: [RouterModule]
)
export class SecurityRoutingModule  


@NgModule(
    imports: [RouterModule.forChild(routes)],
    exports: [RouterModule]
)
export class SecurityRoutingModule  

在您问之前,我还尝试将警卫单独放在 CanActivateCanActivateChildCanLoad 中,以防止任何冲突(如果我了解文档,则不应该存在。)

我错过了什么吗?是一种通缉行为还是我应该在官方 repo 上打开一个错误?

感谢任何愿意花时间在这方面的人

【问题讨论】:

【参考方案1】:

CanLoad 决定是否可以从服务器加载惰性模块。加载后,将不会再次检查(除非您按 F5)。我猜你需要声明两次,一次在CanLoad(如果你根本不想加载代码),一次在CanActivate,如果你想限制访问。


  path: AppRoutes.security,
  canLoad: [SFWIsSysAdmGuard],
  canActivate: [SFWIsSysAdmGuard],
  loadChildren: () => import('./security/security.module').then(mod => mod.SecurityModule)
,

【讨论】:

嘿!太感谢了!正如我所想,我做错了什么,你解释的很有意义!试过了,谢谢,我学到了一些新东西:)

以上是关于Angular CanLoad 防护仅在第一次延迟加载时触发一次?的主要内容,如果未能解决你的问题,请参考以下文章

为啥路由保护 canLoad 不会触发,但 canActivate 会

如何在 Angular js 的选项卡集中启用延迟加载?

仅在第一次加载 Angular 网页时使用 Safari 接收 401 状态

Angular 反应复选框仅在第一次单击后正确切换

Angular 6 - 指定延迟加载块的路径

typescript 路由守卫:CanActive,CanActivateChild,CanLoad和CanDeactivate