Angular 即使路由器导航到不受保护的元素 2,路由器也会调用元素 1 的 canActivate

Angular router calls canActivate of element 1 even if router navigates to unguarded element 2

我有两个组件:HomeComponent 由 AuthGuard 保护,LoginComponent 没有任何保护。

当我从 HomeComponent 调用 logout() 时,我从 localStorage 销毁令牌并调用 this.router.navigate(['/login'])。这会在一瞬间将我重定向到 LoginComponent;然后我的应用程序就像我试图直接调用 HomeComponent 并因此再次调用 canActivate() 函数一样,这导致应用程序完全重新加载。

以下是我的部分代码:

注销功能

   logout() {
        // remove user from local storage to log user out
        localStorage.removeItem('currentUser');
        this.router.navigate(['/login']);
        this.currentUserSubject.next(null);
    }

app.routing.ts

    { path: 'login', component: LoginComponent },
    { path: '', component: HomeComponent, canActivate: [AuthGuard] },

我的 AuthGuard canActivate()

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        const currentUser = this.authenticationService.currentUserValue;
        if (currentUser) {
            // authorised so return true
            return true;
        }

        // not logged in so redirect to login page with the return url
        this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }});
        return false;
    }

我希望应用程序不会重新加载,它只会转到 /login。我怎样才能做到这一点?

编辑 1 我尝试在 stackblitz here 中创建我的应用程序的迷你版本。我是 Angular 的新手,因此在那里重现问题时我没有遇到什么问题。 单击演示中的登录按钮后,会创建一个 localStorage 项,但路由器不会导航到 /。请您从浏览器 URL 中删除 /login... 部分,然后按回车键重新加载页面。您将看到该应用程序的行为方式。 尝试注销并查看问题。

我猜你有一个 this.currentUserSubject.next(null); 的订阅者,它加载了你的 HomePage。这当然指向 /login。一种解决方案是检查订阅者中的 null

重新加载是因为您正在使用

<a href="" ...>

注销。这告诉浏览器导航到当前 URL(即重新加载页面)。

您应该使用按钮,而不是 link。如果您使用 link,至少要防止 link:

的默认操作
(click)="logout($event)"

logout(event: Event) {
    // ...
    event.preventDefault();
}

Demo