4

I have following problem. I have made a CanActivate Guard where if you are logged in you can "go" to Debts Component. My problem is when I am logged in and i want to redirect User to Debts Component ( because RegistrationComponent is default ), but it's not working ( actually my page is blocking.. And i cannot do anything ). My CanActivate function

export class AuthGuardService implements CanActivate {

constructor(private router: Router) { }

canActivate(): Promise<boolean>{
    return checkIfAuth().then(() => {
        setLoggedIn(true);
        this.router.navigate(['/debts']); // <- broken :(
        return true;
    }).catch(() => {
        setLoggedIn(false);
        this.router.navigate(['/login']); // <- broken :(
        return false;
    })
  }
}


export function checkIfAuth () {
return new Promise((resolve, reject) => {
    firebase.auth().onAuthStateChanged((user) => {
        if(user){
            return resolve(true);
        }
        else{
            return reject(false);
        }
    })
  })
}

any my app.routing

const APP_ROUTES: Routes = [
    { path: '', redirectTo: '/registration', pathMatch: 'full' },
    {  path: 'registration', component: RegistrationComponent },
    { path: 'login', component: LoginComponent },
    { path: 'myaccount', component: AccountComponent, canActivate: [AuthGuardService]},
    { path: 'debts', component: DebtsComponent, canActivate: [AuthGuardService]}
];
7
  • There is something I don't understand in your post. What is the exact problem ? You want the user to go to DebtsComponent if he is already logged In ? How do you reach the LoginComponent ? Commented Jan 12, 2017 at 9:14
  • I reach the loginComponent from Menu :) When i am logged in it looks like ( Debts Account SingOut ) and when not ( Registration Log In ). My problem is : I want to redirect User ALWAYS ( when he is logged ) to DebtsComponent ( when he wants to reach Login/Registration Component ) and redirect USER ALWAYS ( when he is not logged in ) to LoginComponent ( when he wants to reach Debts/Account Component ). Commented Jan 12, 2017 at 9:22
  • We might need the code when you login, but my hint would be that on Login, you should try to navigate to your Debts component, and in your guard only return true if the user is loggedIn (and not navigate in your guard). Commented Jan 12, 2017 at 9:34
  • Yes, yes i did it and it works ( it's not a problem :D ). Look, after you are logged in, you are redirected to localhost/debts and it's ok, but USER can change the URL by himself ( localhost/login ) and i want to redirect him, when he is logged ( because you cannot login when you are already logged :P ). Do you know what am i talking about? :( Commented Jan 12, 2017 at 9:48
  • Oh alright. I get it now. Commented Jan 12, 2017 at 9:57

1 Answer 1

5

What I did was kind of a hack but it works flawlessly :

First, I did setup a Guard on my LoginCompoment route.

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

And then I use the RouterStateSnapshot to get a single instance of my URL state, indicating me what the user tried to reach.

I can then manage the cases in the Guard :

import { CanActivate, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';

...

/**
 *  Protects the routes to reach with authentication
 */
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
    // Set user authentication state depending on the token's existance
    this.authService.setLoggedInState();
    // Check user authentication state
    if (this.authService.isAuthenticated) {
        // Explicit navigation to '/login' while the user is already authenticated
        if (state.url === '/login') {
            this.router.navigate(['/dashboard']); // Debts for you
        }
        return true;
    } else {
        // Allow route to './login' to get authenticated
        if (state.url === '/login') {
            return true;
        }
        // Explicit navigation to any URL while not being authenticated
        this.router.navigate(['/login']);
        return false;
    }
}

Documentation link about Snapshots : https://angular.io/docs/ts/latest/guide/router.html#!#sts=Snapshot:%20the%20no-observable%20alternative

To make it work in your case, you just have to adapt the setLoggedInState() to your case which it seems you already have.

N.B : I call this solution a HACK because you actually set a guard on the Login while it will still allow the user to reach it even if he is not authenticated. Still works well tho.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you very much :) Actually had to "change" a little bit this code, but works very good! Thanks :)
No problem ! Glad I could help :)
@AlexBeugnet I would not call it a hack though, everything looks legitimate to me. How your Guard behaves is completely up to you. Generally speaking, basing your Guard's decision on the ActivatedRouteSnapshot also allows you to recycle a single Guard for different routes instead of creating several individual Guards for different routes.