3

I'm implementing a CanActivate guard to redirect the user to the login page if their session is invalid.

The check as to whether the session is valid or not is done through a service and so from the guard I'm subscribing to the service call to get the session validity state.

I've debugged the code and everything seems to be working as it should, in fact when the session is invalid the app does redirect back to the login page. However when I return true from the guard, the page is not loaded.

My code is similar to what is listed on the Angular documentation (Code on Plunker).

I'm not sure whether I've implemented something wrong in the guard itself. The difference that I can see is that the guard is accessing a property in the service - but I don't think that should matter much. From what I can understand returning true from the guard would simply continue the normal routing operation.

Note: I'm using Angular RC3

Code:

Guard

export class MyGuard implements CanActivate {
    constructor(private checkSessionService: CheckSessionService, private router: Router) {}

    canActivate(
    next:  ActivatedRouteSnapshot,
    state: RouterStateSnapshot
    ) {
        this.checkSessionService.checkUserSession(localStorage.getItem('userToken'))
        .subscribe(validSessionReturn => {

            if (validSessionReturn) {
                return true;
            } else {
                // redirect to login
                this.router.navigateByUrl('/login');
                return false;
            }
        },
        error => console.log(error));
    }
}

Edit

I've investigated further and it looks like the issue I'm having is related to the fact that I'm trying to return the boolean from the subscribe method itself. As a test I've tried the following and everything worked as expected:

export class MyGuard implements CanActivate {
    constructor(private checkSessionService: CheckSessionService, private router: Router) {}

    canActivate(
    next:  ActivatedRouteSnapshot,
    state: RouterStateSnapshot
    ) {
        if(localStorage.getItem('userToken') !== null) {
            return true; // or return Observable.of(true);
        } else {
            return false; // or return Observable.of(false);
        }
    }
}

You can notice from the above code that one can return either a boolean or an Observable<boolean>. The CheckSessionService I've implemented does return an Observable<boolean>. In fact when I tried the code below, once again everything worked as expected, meaning that if the session is valid the page is loaded successfully, otherwise routing is stopped:

export class MyGuard implements CanActivate {
    constructor(private checkSessionService: CheckSessionService, private router: Router) {}

    canActivate(
    next:  ActivatedRouteSnapshot,
    state: RouterStateSnapshot
    ) {
        return this.checkSessionService.checkUserSession(localStorage.getItem('userToken'));
    }
}

However with the above example I can't find a way to redirect to a specific page based on the value retrieved by the service. My question now is whether there's a way to check the result of this.checkSessionService.checkUserSession(localStorage.getItem('userToken')) without a subscribe method, or there's a different way how to return from the subscribe method. I did try:

if(this.checkSessionService.checkUserSession(localStorage.getItem('userToken')) === Observable.of(false))

but as expected it did not work.

1 Answer 1

2

Replace

this.checkSessionService...

by

return this.checkSessionService...

Instead of subscribing to the observable and return the subscrption, you must also return the observable itself, but plug something in case it's false:

return this.checkSessionService.checkUserSession(localStorage.getItem('userToken'))
    .do(‌​function(authenticated) { 
        if (!authenticated) ... 
    });
Sign up to request clarification or add additional context in comments.

6 Comments

I did give this a go before. However doing that with the code I have would be returning a Subscription instead of a boolean or Observable<boolean> which is not allowed. I'm sure the code I have is fine, it's just that when returning true it's acting as if I'm returning false and stops the routing operation.
Your reply seems to have pointed me in the right direction but I have a minor issue, I've updated the question with my findings.
Yes, I was a little too fast on answering, and confused promises with Observables. Basically, you need to return an Observable<boolean>, which is what your service returns, but you must also do something if the boolean is false. That's what the do operator allows doing. reactivex.io/documentation/operators/do.html. `return this.checkSessionService.checkUserSession(localStorage.getItem('userToken')).do(function(authenticated) { if (!authenticated) ... });
Perfect! Just updated my code and all is okay! I do need to get to know Observables a bit more :) So far all I've used is the subscribe function and thought it should be working in this case as well but I was wrong. Thanks a lot for your help. :)
I suffer a lot with them, too :)
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.