简体   繁体   中英

angular 2 Auth guard breaks redirect

This is my app-routing.module.ts :

const routes: Routes = [
  { path: '', redirectTo: '/app/elements', pathMatch: 'full' },
  {path: 'app', component:ElementsComponent, children:[
    { path: 'details/:id', component: ElementDetailComponent, canActivate:[AuthGuard]},
    { path: 'elements',     component: ElementListComponent, canActivate:[AuthGuard] },

    { path: 'user/signup',     component: SignupComponent },
    { path: 'user/login',     component: LoginComponent },
    { path: 'user/logout',     component: LogoutComponent }
  ]}

];
@NgModule({
  imports: [ RouterModule.forRoot(routes) ],
  exports: [ RouterModule ],
  providers: [AuthGuard]
})
export class AppRoutingModule {}

As you can see for the path '' I am redirecting to /app/elements which is kind of my home page. This was working fine until I implemented the AuthGuard which looks like:

@Injectable()
export class AuthGuard implements CanActivate{

  public allowed: boolean;

  constructor(private af: AngularFire, private router: Router) { }


  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    this.af.auth.subscribe((auth) =>  {
      if(auth == null) {
        this.router.navigate(['/app/user/login']);
        this.allowed = false;
      } else {
        this.allowed = true;
      }
    });
    return this.allowed;
  }
}

Now, if the user is not logged in and goes to http://localhost:4200/ , the redirect works and it tries to go to http://localhost:4200/app/elements , the guard detects the user is not logged in and it redirects to the login page.

The problem is if the user is logged in and tries to go to http://localhost:4200/ . In this case, nothing happens, the user stays at that URL with the page blank.

Why the redirect is not working in that case? Is there a way to fix that?

the canActivate returns before the firebase observable resolves, so canActivate will always return false, but canActivate can return a promise or an Observable.

that should work :

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.af.auth
                  .map(auth => auth != null)      // null means not authenticated
                  .do(isAuthenticated => {   // change routes if not authenticated
                     if(!isAuthenticated) {
                       this.router.navigate(['/app/user/login']);
                     }
                  });

}

You can use a service that keeps the the state of the authentication. After that just use a code without subscription. Because it's executed async and brakes the code.

public canActivate() {      
    if (this.authService.isAuthenticated) 
      return true;
    this.router.navigate(['/app/user/login']);
    return false;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM