Angular: Run canActivate on each route change

前端 未结 2 1138
后悔当初
后悔当初 2021-02-15 13:50

I got stuck recently with Angular route guards. CanActive runs only once when the page is loaded and does not run on route change within the guarded route. I think this was chan

2条回答
  •  天涯浪人
    2021-02-15 14:29

    Faced the same issue and all I was able to find on issue are few closed issues on Github with Angular devs statements that such behavior "is by design".

    So what I ended up doing is subscribing on navigation events in app.component and firing AuthGuard check there:

    constructor(
      private router: Router,
      private route: ActivatedRoute,
      private authGuard: AuthGuard,
    ) {}
    
    ngOnInit() {
      this.router.events
        .subscribe(event => {
          if (event instanceof RoutesRecognized) {
            this.guardRoute(event);
          }
        }));
    }
    
    private guardRoute(event: RoutesRecognized): void {
      if (this.isPublic(event)) {
        return;
      }
    
      if (!this.callCanActivate(event, this.authGuard)) {
        return;
      }
    }
    
    private callCanActivate(event: RoutesRecognized, guard: CanActivate) {
      return guard.canActivate(this.route.snapshot, event.state);
    }
    
    private isPublic(event: RoutesRecognized) {
      return event.state.root.firstChild.data.isPublic;
    }
    

    AuthGuard is rather standard:

    @Injectable()
    export class AuthGuard implements CanActivate{
    
      constructor(private auth: AuthService, private router: Router) { }
    
      canActivate(): Promise {
        return this.auth.isLoggedInPromise()
          .then(isLoggedIn => {
            if (!isLoggedIn) {
              this.router.navigate(["/login"]);
            }
            return isLoggedIn;
          });
        }
      }
    

    And public routes should be configured like this:

    {
      path: "login",
      component: LoginComponent,
      data: { isPublic: true }
    }
    

    The plus of such implementation is that everything is protected by default and public route should be configured explicitly, which will reduce the possibility of leaving some routes unprotected. Will also refactor this into some kind of service, to be able to use it across multiple apps.

    Inspired by this answer.

提交回复
热议问题