我正在尝试使用AuthGuard
中间件来保护经过身份验证的路由。当我将此中间件实现为路由时。在我激活后卫后,这些路线将失效。
应用程序路由模块
const routes: Routes = [
{
path: 'posts',
canLoad: [AuthGuardMiddleware],
loadChildren: () => import('./modules/posts/posts.module').then(m => m.PostsModule)
},
{
path: 'users',
canLoad: [AuthGuardMiddleware],
loadChildren: () => import('./modules/users/users.module').then(m => m.UsersModule)
}
];
@NgModule({
imports: [RouterModule.forRoot(routes, {
preloadingStrategy: PreloadAllModules
})],
exports: [RouterModule]
})
和AuthGuardMiddleware
@Injectable({
providedIn: 'root'
})
export class AuthGuardMiddleware implements CanActivate, CanLoad {
constructor(private authService: AuthService, private router: Router) {
}
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean | UrlTree> {
return this.authService.user.pipe(map(user => {
if (user) {
return true;
}
return this.router.createUrlTree(['/login']);
}));
}
canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> | Promise<boolean> | boolean {
return this.authService.user.pipe(map(user => {
if (user) {
return true;
}
this.router.navigate(['/']);
return false;
}));
}
}
我该如何解决? 注意:AuthService ::用户类型为BehaviorSubject,初始化为null
更新
我意识到,当我清理我的应用程序组件并删除有条件的路由器插座时,一切都开始正常工作。我仍然不知道是什么导致了此错误。
应用程序组件
export class AppComponent implements OnInit {
currentUrl: string;
isAuthRoute = false;
constructor(private router: Router) {
}
ngOnInit() {
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.currentUrl = event.url;
this.isAuthRoute = ['/login', '/register']
.indexOf(this.currentUrl) !== -1;
}
});
}
}
应用程序组件视图
<div *ngIf="!isAuthRoute">
<div class="row page-wrapper">
<div class="col-md-3 col-md-pull-9">
<app-sidebar></app-sidebar>
</div>
<div class="col-md-9 col-md-push-3 content-area">
<router-outlet></router-outlet>
</div>
</div>
</div>
<div style="height: 80vh" class="d-flex justify-content-center align-items-center" *ngIf="isAuthRoute">
<router-outlet ></router-outlet>
</div>
答案 0 :(得分:1)
您的AuthService.user
返回一个Observable流,但它永远不会完成。据我所知,canLoad
和canActivate
需要完整的Observable
。您可以使用take(1)
运算符来做到这一点:
canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<boolean | UrlTree> {
return this.authService.user.pipe(
map(user => {
if (user) {
return true;
}
return this.router.createUrlTree(['/login']);
}),
take(1)
);
}
canLoad(route: Route, segments: UrlSegment[]): Observable<boolean> | Promise<boolean> | boolean {
return this.authService.user.pipe(
map(user => {
if (user) {
return true;
}
this.router.navigate(['/']);
return false;
}),
take(1)
);
}
我猜这可能发生的另一个原因是,因为您使用的是PreloadAllModules
策略。这将立即加载所有模块,但是我猜这是在用户尚未登录时完成的,因此防护措施将返回false,模块将不会加载,也不会重试。
因此,如果您要使用canLoad
,则需要重新考虑是否要使用PreloadAllModules
保护。也许canActivate
警卫就足够了。
您还可以实现自定义的预加载策略,该策略以某种方式等待用户登录以加载它
有了有关条件路由器出口的其他信息,这很有意义,因为首先将组件放置在一个router-outlet
中,但是在完成路由之后,另一个router-outlet
将变得可见,但没有放置任何东西:)。您可以利用ngTemplateOutlet
指令来规避此问题,从而更新模板:
<ng-template #outlet>
<router-outlet ></router-outlet>
</ng-template>
<div *ngIf="!isAuthRoute">
<div class="row page-wrapper">
<div class="col-md-3 col-md-pull-9">
<app-sidebar></app-sidebar>
</div>
<div class="col-md-9 col-md-push-3 content-area">
<ng-component [ngTemplateOutlet]="outlet"></ng-component>
</div>
</div>
</div>
<div style="height: 80vh" class="d-flex justify-content-center align-items-center" *ngIf="isAuthRoute">
<ng-component [ngTemplateOutlet]="outlet"></ng-component>
</div>
这样,您可以确保在router-outlet
中仅放置一个AppComponent
,这是应该这样做的方式
答案 1 :(得分:0)
我看不到您在AppRoutingModule中使用AuthGuard的地方。
尝试将其应用于任何路线,例如:
{
path: 'posts',
canLoad: [AuthGuard],
loadChildren: () => import('./modules/posts/posts.module').then(m => m.PostsModule),
},