mario595
mario595

Reputation: 3761

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?

Upvotes: 1

Views: 1615

Answers (2)

El houcine bougarfaoui
El houcine bougarfaoui

Reputation: 37343

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']);
                     }
                  });

}

Upvotes: 4

Roman C
Roman C

Reputation: 1

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;
}

Upvotes: 0

Related Questions