Angular身份验证守卫与路由的无限循环 – 如何修复?

huangapple go评论77阅读模式
英文:

Angular Auth guard infinity loop with routing - how to fix it?

问题

我有问题与我的身份验证守卫逻辑和路由。

我在我的 app-routing.module.ts 中有3个路由:

const routes: Routes = [
  {
    path: '',
    loadChildren: () => import('./browse/browse.module').then(m => m.BrowseModule),
  },
  {
    path: AppRoutes.auth,
    loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)
  },
  {
    path: AppRoutes.landing,
    loadChildren: () => import('./landing/landing.module').then(m => m.LandingModule),
  },
];

如您所见,有1个包含 '' 的路径,会将用户发送到 BrowserModule/browser 路径。

browser-routing.module.ts 中,我有一个 AuthGuard,如果用户未登录,将其重定向到 landing 页:

const routes: Routes = [
  {
    path: '',
    component: BrowseComponent,
    redirectTo: BrowseRoutes.browse,
  },
  {
    path: BrowseRoutes.browse,
    loadChildren: () => import('./home/home.module').then(m => m.HomeModule),
    canActivate: [AuthGuard]
  }
];

AuthGuard.ts

canActivate(
  route: ActivatedRouteSnapshot
): Observable<boolean> | Promise<boolean> | boolean {
  if (this.authService.hasToken()) {
    if (this.authService.isAuthenticated()) {
      console.log('logged in guard');
      this.router.navigate(['browse']);
      return true;
    } else {
      console.log('not logged in guard');
      this.router.navigate(['landing']);
      return false;
    }
  } else {
    console.log('no token not logged in guard');
    this.router.navigate(['landing']);
    return false;
  }
}

问题是

如果我已登录,AuthGuard 会进入 无限循环,不断打印“not logged in”,然后进入 / 再次进入 /browse,然后再次进入“logged in”并再次进入无限循环。如何解决这个问题?

英文:

I am having problems with my auth guard logic and routing.

I have 3 routes in my app-routing.module.ts :

const routes: Routes = [
  {
    path: &#39;&#39;,
    loadChildren: () =&gt; import(&#39;./browse/browse.module&#39;).then(m =&gt; m.BrowseModule),
  },
  {
    path: AppRoutes.auth,
    loadChildren: () =&gt; import(&#39;./auth/auth.module&#39;).then(m =&gt; m.AuthModule)
  },
  {
    path: AppRoutes.landing,
    loadChildren: () =&gt; import(&#39;./landing/landing.module&#39;).then(m =&gt; m.LandingModule),
  },
];

As you can see there are 1 path which contains &#39;&#39; and will send the user there - BrowserModule - /browser path

In the browser-routing.module.ts I have AuthGuard which sends users to landing page if they are not logged in :

const routes: Routes = [
  {
    path: &#39;&#39;,
    component: BrowseComponent,
    redirectTo: BrowseRoutes.browse,
  },
  {
    path: BrowseRoutes.browse,
    loadChildren: () =&gt; import(&#39;./home/home.module&#39;).then(m =&gt; m.HomeModule),
    canActivate: [AuthGuard]
  }
];

AuthGuard.ts :

  canActivate(
    route: ActivatedRouteSnapshot
  ): Observable&lt;boolean&gt; | Promise&lt;boolean&gt; | boolean {
    if (this.authService.hasToken()) {
        if(this.authService.isAuthenticated()){
          console.log(&#39;logged in guard&#39;);
          this.router.navigate([&#39;browse&#39;]);
            return true;
        } else {
          console.log(&#39;not logged in guard&#39;);
            this.router.navigate([&#39;landing&#39;]);
            return false;
        }
    } else {
      console.log(&#39;no token not logged in guard&#39;);
      this.router.navigate([&#39;landing&#39;]);
      return false;
    }


  }

The problem is :

If I am logged in, it goes infinity loop with AuthGuard, printing me either "not logged in" and going in "/" then /browse again and again either "logged in" and in infinity pool again. How to fix it ?

答案1

得分: 6

不需要在满足条件时从守卫中导航。这会导致守卫覆盖它不应该负责的决策,并使它无法重用于其他路由,因为它将始终导航到 /browse。守卫的工作是验证,只有在条件不满足时才应导航。
您的 canActivate 方法应具有以下结构:

if (isLoggedIn()) {
  return true;
}
this.router.navigate(['landing']);
return false;
英文:

There's no need to navigate from the guard when the condition is met. This makes the guard override the decision that it should not be responsible for and renders it impossible to reuse for other routes as it will always navigate to /browse. The guard's job is to validate and should only navigate when a condition is not met.
Your canActivate method should have the following structure:

if (isLoggedIn()) {
  return true;
}
this.router.navigate([&#39;landing&#39;]);
return false;

答案2

得分: 0

Angular Routing
来自Angular文档"https://angular.io/guide/router"

配置中路由的顺序很重要,这是有意设计的。路由器在匹配路由时使用首次匹配策略,因此更具体的路由应该放在不太具体的路由之上。在上面的配置中,首先列出了具有静态路径的路由,然后是一个空路径路由,该路由匹配默认路由。通配符路由最后出现,因为它匹配每个URL,只有在没有其他路由首先匹配时才应选择它。

我看到你的路由总是匹配到第一个路由'browser.module'。Angular使用'首次匹配策略'。

所以将路由更改为以下内容:

const routes: Routes = [
  {
    path: AppRoutes.auth,
    loadChildren: () => import('./auth/auth.module').then(m => m.AuthModule)
  },
  {
    path: AppRoutes.landing,
    loadChildren: () => import('./landing/landing.module').then(m => m.LandingModule),
  },
  {
    path: '',
    loadChildren: () => import('./browse/browse.module').then(m => m.BrowseModule),
  },
];
英文:

Angular Routing
From angular docs "https://angular.io/guide/router"
> The order of the routes in the configuration matters and this is by design. The router uses a first-match wins strategy when matching routes, so more specific routes should be placed above less specific routes. In the configuration above, routes with a static path are listed first, followed by an empty path route, that matches the default route. The wildcard route comes last because it matches every URL and should be selected only if no other routes are matched first.

I see your route always matches to the first route 'browser.module'. angular uses 'first-match wins strategy'

So change the route to below

const routes: Routes = [
  
  {
    path: AppRoutes.auth,
    loadChildren: () =&gt; import(&#39;./auth/auth.module&#39;).then(m =&gt; m.AuthModule)
  },
  {
    path: AppRoutes.landing,
    loadChildren: () =&gt; import(&#39;./landing/landing.module&#39;).then(m =&gt; m.LandingModule),
  },
  {
    path: &#39;&#39;,
    loadChildren: () =&gt; import(&#39;./browse/browse.module&#39;).then(m =&gt; m.BrowseModule),
  },
];

huangapple
  • 本文由 发表于 2020年1月6日 15:07:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/59607988.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定