简体   繁体   中英

Verify token with API in Angular8 canActivate method of AuthGuard

I want to do some validation on each refresh request for some routes. So I'm using Angular AuthGuard . The problem is in canActivate method I want to perform validation with online API.

API is /token/verify which simply gets token variable (jwt) and verify if it's true or false. Then if verify is not complete will route to /login page else do the rest.

Here is the code:

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | boolean {
let token = this.auth.getToken();
let url = '/token/verify/';
if (!token) {
  this.router.navigate(['/login']);
  return false;
}
this.auth.verifyToken().then(res => {
  return true;
}).catch(err => {
  this.router.navigate(['/login']);
  return false;
})

and the verifyToken method is like this:

verifyToken(): Promise<boolean> {
    let token = this.getToken();
    return !token ?
        new Promise<boolean>(resolve => {
            resolve(false);
            return false;
        }) :
        this.http.post(this.url + '/token/verify/', { 'token': token })
            .toPromise()
            .then((res) => {
                localStorage.data = JSON.stringify(res);//(res.json());
                return true;
            }
            ).catch((error) => {
                return false
            });
}

Problem is that the promise call doesn't work and will be passed. I mean the first part that does check it from localstorage works fine. But the next part that checks it with online API will not work. and authGuard doesn't wait for its response to do the routing.

I guess it should be in some async/await manner. But I did some tests and none of them worked. Will be glad if anyone could help me.

I think you'll be able to simplify the whole implementation if you use Observable s instead.

If you do consider that proposal, then your verifyToken method could be refactored to this:

import { of, Observable } from 'rxjs';

verifyToken(): Observable<boolean> {
  const token = this.getToken();
  return token ? this.http
    .post(this.url + '/token/verify/', {
      'token': token
    })
    .pipe(
      tap(res => localStorage.data = JSON.stringify(res)),
      map(
        res => true,
        error => false
      )
    ) : of(false)
}

And then in your Guard, you'd simply do this:

canActivate(
  next: ActivatedRouteSnapshot,
  state: RouterStateSnapshot
): Observable < boolean > | Promise < boolean > | boolean {
  const token = this.auth.getToken();
  const url = "/token/verify/";

  if (!token) {
    this.router.navigate(['/login']);
    return false;
  }

  return this.auth.verifyToken().pipe(
    catchError(err => {
      console.log('Handling error locally and rethrowing it...', err);
      this.router.navigate(['/login']);
      return of(false);
    })
  );

}

Here's a Working Demo for your ref.

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