Angular: 运行 canActivate 每次路由更改
Angular: Run canActivate on each route change
我最近被 Angular 路由守卫卡住了。 CanActive 运行 仅在页面加载时触发一次,并且不会 运行 在受保护路由内的路由更改上。我认为这已更改,因为它过去每次更改时都会 运行 。根据我在论坛中阅读的内容,我应该使用 CanActivateChild。问题是,我们的应用程序由几个模块组成,这些模块有几个路由后代,当我在根模块中使用 CanActivateChild 时,它会在更改路由时被调用多次。
我觉得为每个子模块分配一个守卫是愚蠢的,因为对于 AppModule,那些延迟加载的子模块应该只是 'Black Boxes',我想定义所有这些模块都应该被守卫。
export const routes: Routes = [
{
path: '404',
component: NotFoundComponent
},
{
path: '',
canActivate: [AuthGuard],
component: FullLayoutComponent,
data: {
title: 'Home'
},
children: [
{
path: 'administration',
loadChildren: './administration/administration.module#AdministrationModule'
},
{
path: 'settings',
loadChildren: './settings/settings.module#SettingsModule'
}
]
},
{
path: '',
loadChildren: './account/account.module#AccountModule'
},
{
path: '**',
redirectTo: '404'
}
];
有什么解决办法吗?或者您认为这是关于安全的 'not an issue'?
谢谢大家。
遇到了同样的问题,我能找到的所有问题都是 Github 上的几个已解决问题 Angular 开发人员声明这种行为 "is by design".
所以我最后做的是订阅 app.component 中的导航事件并在那里触发 AuthGuard 检查:
constructor(
private router: Router,
private route: ActivatedRoute,
private authGuard: AuthGuard,
) {}
ngOnInit() {
this.router.events
.subscribe(event => {
if (event instanceof RoutesRecognized) {
this.guardRoute(event);
}
}));
}
private guardRoute(event: RoutesRecognized): void {
if (this.isPublic(event)) {
return;
}
if (!this.callCanActivate(event, this.authGuard)) {
return;
}
}
private callCanActivate(event: RoutesRecognized, guard: CanActivate) {
return guard.canActivate(this.route.snapshot, event.state);
}
private isPublic(event: RoutesRecognized) {
return event.state.root.firstChild.data.isPublic;
}
AuthGuard 比较标准:
@Injectable()
export class AuthGuard implements CanActivate{
constructor(private auth: AuthService, private router: Router) { }
canActivate(): Promise<boolean> {
return this.auth.isLoggedInPromise()
.then(isLoggedIn => {
if (!isLoggedIn) {
this.router.navigate(["/login"]);
}
return isLoggedIn;
});
}
}
和public路由应该这样配置:
{
path: "login",
component: LoginComponent,
data: { isPublic: true }
}
这种实现的优点是默认情况下一切都受到保护,并且 public 路由应该明确配置,这将减少一些路由不受保护的可能性。还将把它重构为某种服务,以便能够跨多个应用程序使用它。
灵感来自 this answer。
订阅路由器事件的问题是导航已经开始,历史已经更新,这很难像守卫那样可靠地阻止导航。
但是 Angular 已经学会了为您提供一种方法来配置守卫和解析器应该如何直接在您的 routes.ts
:
中运行
export const routes: Routes = [
{
path: '404',
component: NotFoundComponent
},
{
path: '',
canActivate: [AuthGuard],
runGuardsAndResolvers: 'always',
children: [
....
]
}
]
这是文档:https://angular.io/api/router/RunGuardsAndResolvers
有一篇很好的博文解释了您的选择:https://juristr.com/blog/2019/01/Explore-Angular-Routers-runGuardsAndResolvers/
我最近被 Angular 路由守卫卡住了。 CanActive 运行 仅在页面加载时触发一次,并且不会 运行 在受保护路由内的路由更改上。我认为这已更改,因为它过去每次更改时都会 运行 。根据我在论坛中阅读的内容,我应该使用 CanActivateChild。问题是,我们的应用程序由几个模块组成,这些模块有几个路由后代,当我在根模块中使用 CanActivateChild 时,它会在更改路由时被调用多次。
我觉得为每个子模块分配一个守卫是愚蠢的,因为对于 AppModule,那些延迟加载的子模块应该只是 'Black Boxes',我想定义所有这些模块都应该被守卫。
export const routes: Routes = [
{
path: '404',
component: NotFoundComponent
},
{
path: '',
canActivate: [AuthGuard],
component: FullLayoutComponent,
data: {
title: 'Home'
},
children: [
{
path: 'administration',
loadChildren: './administration/administration.module#AdministrationModule'
},
{
path: 'settings',
loadChildren: './settings/settings.module#SettingsModule'
}
]
},
{
path: '',
loadChildren: './account/account.module#AccountModule'
},
{
path: '**',
redirectTo: '404'
}
];
有什么解决办法吗?或者您认为这是关于安全的 'not an issue'?
谢谢大家。
遇到了同样的问题,我能找到的所有问题都是 Github 上的几个已解决问题 Angular 开发人员声明这种行为 "is by design".
所以我最后做的是订阅 app.component 中的导航事件并在那里触发 AuthGuard 检查:
constructor(
private router: Router,
private route: ActivatedRoute,
private authGuard: AuthGuard,
) {}
ngOnInit() {
this.router.events
.subscribe(event => {
if (event instanceof RoutesRecognized) {
this.guardRoute(event);
}
}));
}
private guardRoute(event: RoutesRecognized): void {
if (this.isPublic(event)) {
return;
}
if (!this.callCanActivate(event, this.authGuard)) {
return;
}
}
private callCanActivate(event: RoutesRecognized, guard: CanActivate) {
return guard.canActivate(this.route.snapshot, event.state);
}
private isPublic(event: RoutesRecognized) {
return event.state.root.firstChild.data.isPublic;
}
AuthGuard 比较标准:
@Injectable()
export class AuthGuard implements CanActivate{
constructor(private auth: AuthService, private router: Router) { }
canActivate(): Promise<boolean> {
return this.auth.isLoggedInPromise()
.then(isLoggedIn => {
if (!isLoggedIn) {
this.router.navigate(["/login"]);
}
return isLoggedIn;
});
}
}
和public路由应该这样配置:
{
path: "login",
component: LoginComponent,
data: { isPublic: true }
}
这种实现的优点是默认情况下一切都受到保护,并且 public 路由应该明确配置,这将减少一些路由不受保护的可能性。还将把它重构为某种服务,以便能够跨多个应用程序使用它。
灵感来自 this answer。
订阅路由器事件的问题是导航已经开始,历史已经更新,这很难像守卫那样可靠地阻止导航。
但是 Angular 已经学会了为您提供一种方法来配置守卫和解析器应该如何直接在您的 routes.ts
:
export const routes: Routes = [
{
path: '404',
component: NotFoundComponent
},
{
path: '',
canActivate: [AuthGuard],
runGuardsAndResolvers: 'always',
children: [
....
]
}
]
这是文档:https://angular.io/api/router/RunGuardsAndResolvers
有一篇很好的博文解释了您的选择:https://juristr.com/blog/2019/01/Explore-Angular-Routers-runGuardsAndResolvers/