首页 > 解决方案 > 为什么当我在 Angular 中路由时没有触发警卫?

问题描述

我创建了惰性路由:一个用于 app shell 模块,另一个用于 auth 模块。

当我单击登录时,我会重定向到 shell 应用程序,这没关系。

但是当我点击注销并重定向到主路由(为了触发警卫)时,警卫似乎没有调用。

我怎么知道?因为单击注销后我看不到控制台输出。

它甚至不会触发问题所在的守卫。所以我不会重定向到登录页面。

是的,当然我可以直接导航到登录路线,但我想为我做这件事。

所以我创建了一个简单的应用程序来演示这里和codesandbox.io中的问题

import { BrowserModule } from "@angular/platform-browser";
import { Injectable, NgModule } from "@angular/core";
import { Component } from "@angular/core";
import {
  ActivatedRouteSnapshot,
  CanActivate,
  CanActivateChild,
  CanLoad,
  Router,
  RouterModule,
  RouterStateSnapshot,
  UrlTree
} from "@angular/router";
import { CommonModule } from "@angular/common";
import { Observable, of } from "rxjs";

let loggedIn = false; // <--- this is demo. it's set if the user login or not.

@Component({
  template: '<button (click)="login()">login</button>'
})
export class LoginComponent {
  constructor(private router: Router) {}

  login() {
    console.log("in login");

    loggedIn = true;
    this.router.navigate(["/"]);
  }
}

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild([{ path: "", component: LoginComponent }])
  ],
  declarations: [LoginComponent]
})
export class AuthModule {}

///////////////////////////////

@Injectable()
export class IsLoggedInGuard implements CanActivate, CanActivateChild, CanLoad {
  constructor(private readonly router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean | UrlTree> {
    return this.isAuthenticated(state.url);
  }

  canActivateChild(): Observable<boolean | UrlTree> {
    return this.isAuthenticated();
  }

  canLoad(): Observable<boolean | UrlTree> {
    return this.isAuthenticated();
  }

  private isAuthenticated(url?: string): Observable<boolean | UrlTree> | any {
    if (!loggedIn) {
      return this.router.createUrlTree(["/auth"], {
        queryParams: { url }
      });
    }
    return true;
  }
}
////

@Component({
  template: '<button (click)="logout()">logout</button>'
})
export class ShellComponent {
  constructor(private router: Router) {}

  logout() {
    console.log("in logout");

    loggedIn = false;
    this.router.navigate(["/"]);
  }
}

@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild([{ path: "", component: ShellComponent }])
  ],
  declarations: [ShellComponent]
})
export class ShellModule {}

@Component({
  selector: "app-root",
  template: `<router-outlet></router-outlet>`
})
export class AppComponent {
  title = "CodeSandbox";
}

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      {
        path: "",
        loadChildren: () => Promise.resolve(ShellModule),
        canActivate: [IsLoggedInGuard]
      },
      { path: "auth", loadChildren: () => Promise.resolve(AuthModule) }
    ])
  ],
  providers: [IsLoggedInGuard],
  bootstrap: [AppComponent]
})
export class AppModule {}

标签: angular

解决方案


您不能这样做,因为您已经在同一个routecanActivate 决定是否可以激活路线”上,但在您的情况下,它在您登录时导航到它后已经被激活。

即使将onSameUrlNavigation配置更改为reload,或RouteReuseStrategy用于在导航到同一路由时重新加载组件,即使这样也不起作用,因为这只会重新加载组件而不会canActivate再次触发防护(因为路由已经激活)。

在您的情况下,最好在注销时将用户重定向到登录页面。


推荐阅读