在 AuthGuard 的 Angular8 canActivate 方法中使用 API 验证令牌

Verify token with API in Angular8 canActivate method of AuthGuard

我想对某些路由的每个刷新请求进行一些验证。所以我使用 Angular AuthGuard。问题出在 canActivate 方法中,我想使用在线 API 执行验证。

API 是 /token/verify,它只是获取 token 变量 (jwt) 并验证它是对还是错。 然后,如果验证未完成,将路由到 /login 页面,否则执行其余操作。

代码如下:

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

verifyToken方法是这样的:

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

问题promise调用不通,将通过。我的意思是从 localstorage 检查它的第一部分工作正常。但是接下来用在线 API 检查它的部分将不起作用。并且 authGuard 不等待其响应进行路由。

我想它应该是某种 async/await 方式。但我做了一些测试,其中 none 有效。如果有人能帮助我,我会很高兴。

我认为如果改用 Observables,您将能够简化整个实施。

如果您确实考虑了该提案,那么您的 verifyToken 方法可以重构为:

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

然后在您的 Guard 中,您只需执行以下操作:

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.