【问题标题】:Angular authentication and route guardAngular 身份验证和路由保护
【发布时间】:2021-12-16 16:35:55
【问题描述】:

我正在构建一个使用 GraphQL 端点的角度 spa 前端。用户登录后,我在 localstorage 上设置令牌,并在我的 AuthService 上设置身份验证状态。我的想法(来自 React)是当 App 组件安装 ngOnInit 我将请求我查询谁将从存储在本地存储中的令牌返回用户,我想在 AuthService 上设置用户。我面临的问题是我创建了一个受保护的仪表板路由,但 AuthGuard 没有等待 App Component ngOnInit 完成,它将重定向到登录页面。

import {Component, OnDestroy, OnInit} from '@angular/core';
import {MeGQL, User} from "../generated/graphql";
import {AuthService} from "./auth.service";
import {Router} from "@angular/router";

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit {
  title = 'frontend';
  loading: boolean = true
  private meSubs: any;

  constructor(private meQuery: MeGQL, private authService: AuthService, private router: Router) {
  }

  async ngOnInit() {
    this.loading = true
    console.log("MONTOU APP")
    this.loading = true
    return this.meQuery.fetch({}, {
      fetchPolicy: "network-only",
    }).toPromise()
      .then(({data}) => {
        console.log("ENTROU NO THEN")
        if (data.me) {
          console.log(data.me)
          this.authService.setUser(data.me)
          this.loading = false
        }
      }).catch(e => {
        this.loading = false
        console.log("ERROR: ", e)
      })
  }


}
{{ loading }}
<div *ngIf="loading">Carregando...</div>
<div *ngIf="!loading">
    <router-outlet></router-outlet>
</div>
import { Injectable } from '@angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from "@angular/router";
import {AuthService} from "../auth.service";
import {Observable} from "rxjs";

@Injectable({
  providedIn: 'root'
})
export class AuthGuardService implements CanActivate{

  constructor(private authService: AuthService, private router: Router) { }

  async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):  Promise<boolean >  {
    console.log("Auth Guard user mount")
    if(!this.authService.isAuthenticated()) {
      console.log("Não autenticado")
      await this.router.navigate(['/login'])
      return false
    }
    return true
  }
}
import {Injectable} from '@angular/core';
import {User, MeQuery, MeDocument, MeQueryVariables} from "../generated/graphql";
import {BehaviorSubject} from "rxjs";
import {Apollo} from "apollo-angular";

export type CurrentUserType = Pick<User, 'id' | 'name' | 'email' | 'active' | 'type'>

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private TOKEN_KEY = "AGENDEI_TOKEN"
  private currentUser: CurrentUserType | null = null
  private _isAuthenticated = new BehaviorSubject(false);
  private authSource = new BehaviorSubject<CurrentUserType | null>(null)


  constructor(private apollo: Apollo) { }

  loginUser(user: CurrentUserType, accessToken: string) {
    localStorage.setItem(this.TOKEN_KEY, accessToken)
    this.setUser(user)
    this._isAuthenticated.next(true)
  }

  setUser(user: CurrentUserType) {
    this.currentUser = user
  }

  async logout() {
    localStorage.removeItem(this.TOKEN_KEY)
    await this.apollo.getClient().resetStore()
    this._isAuthenticated.next(false);
  }

  public isAuthenticated(): Boolean {
    return this._isAuthenticated.value
  }

  public getUserFromMeQuery() {
    return this.apollo.query<MeQuery, MeQueryVariables>({
      query: MeDocument
    }).toPromise()
  }

}

【问题讨论】:

    标签: javascript angular typescript authentication


    【解决方案1】:

    我相信在您的警卫服务中更改 canActivate 方法会起作用。

    原因在检查用户是否登录时,您不是在等待身份验证服务设置身份验证状态。

    AuthService
    
     public isAuthenticated(): Promise<boolean> {
        return this._isAuthenticated.toPromise();
      }
    
    AuthGuardService
    
    async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot):  Promise<boolean >  {
        console.log("Auth Guard user mount")
    const isAuthenticated = await this.authService.isAuthenticated()
        if(!isAuthenticated) {
          console.log("Não autenticado")
          await this.router.navigate(['/login'])
          return false
        }
        return true
      }
    
    
    

    【讨论】:

      【解决方案2】:

      尝试在 AppComponent 的 ngOninit 中使用 await:

      async ngOnInit() {
          this.loading = true
          console.log("MONTOU APP")
          this.loading = true
          let response;
          try {
              response = await this.meQuery.fetch({}, {
                                  fetchPolicy: "network-only",
                               }).toPromise()
              let {data} = response;
              if (data.me) {
                 console.log(data.me)
                 this.authService.setUser(data.me)
              }
              this.loading = false
          } catch (err) {
              this.loading = false
              console.log("ERROR: ", err)
          }
       }
      

      【讨论】:

      • 我尝试过这样做,但到目前为止没有成功。
      猜你喜欢
      • 2020-05-10
      • 2021-11-07
      • 2013-12-11
      • 2013-03-27
      • 2020-07-01
      • 1970-01-01
      • 2018-05-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多