如果canLoad或canActivate失败,该如何路由登录而不在AuthGuard本身中进行路由?

时间:2018-09-07 11:32:27

标签: angular angular-routing ngrx auth-guard

所以,这就是我的AuthGuard的样子:

canLoad(route: Route) {
    return this.store.select(fromRoot.getIsAuth).pipe(take(1));
}

我从app.component检查身份验证信息,并仅返回一个Observable布尔值。

我不想订阅此路由以进行重新路由,我不想在AuthGuard中使用router.navigate,所以我想将其保留为简单的Guard。

有没有一种方法可以在路由模块内部进行重新路由,如果AuthGuard返回false,它会简单地路由到备用路径?

2 个答案:

答案 0 :(得分:2)

据我所知,您必须在守卫中进行导航。无法将路由器配置为执行您想要的操作。但是您不需要订阅。您可以使用tap进行导航。

canLoad(route: Route) {
    return this.store.select(fromRoot.getIsAuth)
        .pipe(
            take(1),
            tap(loggedIn => {
                if (!loggedIn) {
                    this.router.navigate(['/login']);
                }
            })
        );
}

答案 1 :(得分:0)

TLDR;如果您直接在OnLoad内部导航,则会得到一个NavigationCancel事件,其中包含有关ID不匹配的消息(并且我讨厌该错误!)。您可以这样避免:

this.routerEvents.navigationCancel$.pipe(take(1)).subscribe(() =>
{           
      this.router.navigateByUrl(result); 
});

return false;

我不确定大多数人何时使用canLoadcanActivate,但是我的具体情况(和解决方案)如下:

  • 我有一个登录对话框,该对话框从我的AuthGuard服务内部显示。 AuthGuard显示对话框,但在用户尝试登录之前不会返回true / false。
  • 如果登录失败并且需要将用户重定向到特定页面(例如支持页面),则AuthGuard服务将返回UrlTree
  • 我的'/ account'路线是延迟加载的,可能要花几秒钟的时间
  • 我希望登录对话框在用户单击“帐户”时立即显示 ,因此添加了CanLoad
  • 因此,我要做的就是将相同的逻辑放入canLoad处理程序中。这意味着canLoad也会在首先被点击时显示一个对话框。
  • 我离开了canActivate后卫来运行完全相同的逻辑(不用担心-您将永远不会看到两个对话框)

在这种情况下,我发现在canLoad中执行以下操作最容易:

canLoad(route: Route, segments: UrlSegment[])
   {
       const currentNavigation = this.router.getCurrentNavigation();
       const isInitialNavigation = !currentNavigation.previousNavigation;

       if (isInitialNavigation)
       {
           return true;   // always allow load for first navigation (avoids other complications)
       }
       else {

           // returns Observable<boolean | UrlTree> 
           return showLoginDialog().pipe(map(result => {

               if (typeof result === 'boolean') {
                  return result;
               }
               else {
                     // we have a URL tree
                    // wait for the expected NavigationCancel event and then navigate
                    this.routerEvents.navigationCancel$.pipe(take(1)).subscribe(() =>
                    {           
                       this.router.navigateByUrl(result); 
                    });
                   return false;
                }
           });;    
       }
}

我在定义的地方也提供了由root提供的RouterEvents服务

  navigationCancel$ = this.router.events.pipe(filter((e): e is NavigationCancel => e instanceof NavigationCancel));

注意:请注意是否选择不包括isInitialNavigation支票。如果您的重定向尝试重定向到主页,则它将无法正常工作,因为路由器认为您已经在该页面上。您可以通过仅重定向到首页的/redirect_home路由来解决此问题-或更改onSameURLNavigation设置。