Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 route guard returning Observable<bool>, how to handle errors

I have a route guard like below

@Injectable()
export class AuthGuard implements CanActivate {

constructor(private router: Router, private authenticationSvc: AuthenticationService) { }

canActivate(): Observable<boolean> {
    return this.authenticationSvc.getAuthenticatedUser().map(
        r => {
            if (this.authenticationSvc.isAuthenticated()) {
                // logged in so return true
                return true;
            }
            this.router.navigateByUrl('/login');
            return false;
        })
}

The issue is that sometimes getAuthenticatedUser returns a 401, and I have an http-interceptor that handles the 401 and redirect to the login page. The issue is that this .map never resolves because the http request throws an error, and the angular router gets stuck on this first routing request and can't handle the subsequent request from the interceptor. How can I handle this error and have the Observable returned resolve to false and keep things moving?

  getAuthenticatedUser() {
         let getUserObservable = this.http.get(ApiUrl + 'security/getAuthenticatedUser')
            .map((res: any) => res.json())
            .share()

        //Get the result for the cache
        getUserObservable.subscribe(
            r => {
                if (r.success) {
                    this.authenticatedUser = r.result.user;
                }
            }); 

        //return the observable
        return getUserObservable;
  } 

and http-intercepter below

export class HttpInterceptor extends Http {
    authSvc: AuthenticationService;
    lastClicked: any = 0;
    constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, private _router: Router, private injector: Injector) {
        super(backend, defaultOptions);
    }
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.request(url, options));
}

get(url: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.get(url, options));
}

post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.post(url, body, this.getRequestOptionArgs(options)));
}

put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.put(url, body, this.getRequestOptionArgs(options)));
}

delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
    return this.intercept(super.delete(url, options));
}

getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
    if (options == null) {
        options = new RequestOptions();
    }
    if (options.headers == null) {
        options.headers = new Headers();
    }
    options.headers.append('Content-Type', 'application/json');
    return options;
}

 intercept(observable: Observable<Response>): Observable<Response> {
    return observable.catch((err, source) => {
        //If we get a 401 from the api that means out FormsAuthenticationTicket has expired, clear the auth cookie and navigate back to terms page
        if (err.status == 401) {
            this._router.navigateByUrl('/login');
        }

        return Observable.throw(err);
    });
}
like image 314
Josh Avatar asked Mar 01 '17 23:03

Josh


People also ask

Which routing guard is used to check whether routing can take place or not?

Angular's route guards are interfaces which can tell the router whether or not it should allow navigation to a requested route. They make this decision by looking for a true or false return value from a class which implements the given guard interface.

Which route Guard would you use to prevent a user from navigating to another view before saving their content?

Now here if we want to prevent navigation of an unauthorized user we can use CanActivate Guard, that will do the job but also download the module. Now to control the navigation as well as prevent downloading of that module we can use CanLoad Guard.

Which route Guard is helpful in preventing unauthorized access to a component?

canActivate: It checks if the user can visit the specific route or we have to prevent access to the specific route. For this, we use the CanActivate interface. Here, the canActivate method has two arguments.

What is AuthGuard angular10?

AuthGuard is used to protect the routes from unauthorized access in angular. How AuthGuard Works? Auth guard provide lifecycle event called canActivate. The canActivate is like a constructor. It will be called before accessing the routes.


1 Answers

You can catch errors and return Observable<bool> as follows:

@Injectable()
export class AuthGuard implements CanActivate {

constructor(private router: Router, private authenticationSvc: AuthenticationService) { }

canActivate(): Observable<boolean> {
    return this.authenticationSvc.getAuthenticatedUser().map(
        r => {
            if (this.authenticationSvc.isAuthenticated()) {
                // logged in so return true
                return true;
            }
            this.router.navigateByUrl('/login');
            return false;
        })
        .catch((error: any) => {
            this.router.navigateByUrl('/login');
            return Observable.of(false);
        });
}
like image 52
seidme Avatar answered Nov 08 '22 15:11

seidme