2

当用户第一次使用他们的凭据登录时,auth guard 允许用户访问管理页面,但是一旦我刷新或转到另一个管理页面,auth guard 会将我重定向回客户端页面,说明我没有访问权限.

auth.guard.ts

import { Injectable } from '@angular/core';
import {
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
  UrlTree,
  CanActivate,
  Router,
} from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';

@Injectable({
  providedIn: 'root',
})
export class AuthGuard implements CanActivate {
  constructor(public authService: AuthService, public router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {
    
    if (this.authService.isLoggedIn() !== true || this.authService.isAuthenticated() == null) {
      window.alert('Access not allowed!');
      this.router.navigate(['']);
    }
    return true;
  }
}

我的身份验证守卫所做的是检查令牌是否存在于本地存储中。如果存在,则通过检索令牌、对其进行解码并将其添加到 get 方法来检查用户是否存在于数据库中。isAuthenticated 函数在第一次尝试时有效,但在随后的尝试中,它甚至根本没有运行,我真的很困惑为什么它没有运行。

身份验证服务.ts

import { Injectable } from '@angular/core';

import { Router } from '@angular/router';
import {
  HttpClient,
  HttpHeaders,
  HttpErrorResponse,
} from '@angular/common/http';

import { Observable, throwError} from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { User } from '../shared/IUser';

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  API_URL: string = 'http://localhost:3000';
  headers = new HttpHeaders().set('Content-Type', 'application/json');
  currentUser = {};
  userId: string;

  
  constructor(private httpClient: HttpClient, public router: Router) {}

  login(user: User): Observable<any> {
    return this.httpClient.post<User>(`${this.API_URL}/login`, user);
  }

  getAccessToken() {
    return localStorage.getItem('access_token');
  }

  isLoggedIn(): boolean {
    let authToken = localStorage.getItem('access_token');
    return authToken !== null ? true : false;
  }

  isAuthenticated() {
    let authToken = this.getAccessToken();
    const claimString = atob(authToken.split('.')[1]);
    const claims = JSON.parse(claimString);


    this.getUserProfile(claims.userId).subscribe((res) => {
      this.userId = res._id;
    });
  
    
    return this.userId;
  }

  logout() {
    if (localStorage.removeItem('access_token') == null) {
      this.router.navigate(['auth']);
    }
  }

  getUserProfile(id): Observable<any> {
    return this.httpClient
      .get(`${this.API_URL}/users/${id}`, { headers: this.headers })
      .pipe(
        map((res: Response) => {
          return res || {};
        }),
        catchError(this.handleError)
      );
  }

  handleError(error: HttpErrorResponse) {
    let msg = '';
    if (error.error instanceof ErrorEvent) {
      // client-side error
      msg = error.error.message;
    } else {
      // server-side error
      msg = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    return throwError(msg);
  }
}

4

1 回答 1

0

您面临的问题与可观察对象的工作方式有关

  isAuthenticated() {
    let authToken = this.getAccessToken();
    const claimString = atob(authToken.split('.')[1]);
    const claims = JSON.parse(claimString);


    this.getUserProfile(claims.userId).subscribe((res) => {
      this.userId = res._id;
    });
  
    
    return this.userId;
  }

因此,您在这里所做的事情是发出一个请求,该请求将在this.userId. 所以发生的事情是,当您尝试访问受保护的路径时,您仍然没有响应,this.getUserProfile因此该字段this.userId未定义。

您可以做的一件事是将代码更改为如下所示

  getAccessToken() {
    return of(localStorage.getItem('access_token'));
  }
...
  isAuthenticated() {
    let authToken = this.getAccessToken();
    const claimString = atob(authToken.split('.')[1]);
    const claims = JSON.parse(claimString);


    return this.getUserProfile(claims.userId)
  }
...

在你的内心深处,你要警惕类似的东西

import { Injectable } from '@angular/core';
import {
  ActivatedRouteSnapshot,
  RouterStateSnapshot,
  UrlTree,
  CanActivate,
  Router,
} from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';

@Injectable({
  providedIn: 'root',
})
export class AuthGuard implements CanActivate {
  constructor(public authService: AuthService, public router: Router) {}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot
  ): Observable<boolean> | Promise<boolean> | boolean {
    return combineLatest([this.authService.isLoggedIn(), this.authService.isAuthenticated()]).pipe(map(([auth, id]) => auth === true && id !== null))

  }
}

这是示例代码,所以可能有一些拼写错误,但我想你会明白的:)

于 2020-06-25T10:34:45.560 回答