首页 > 解决方案 > 如果使用搜索栏导航到 URI,则 Angular 身份验证防护失败

问题描述

我已经在我的应用程序中设置了一个可注入来处理身份验证:

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import {AngularFireAuth} from '@angular/fire/auth';
import {SnackService} from '../../services/snack.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(
      private afAuth: AngularFireAuth,
      private snack: SnackService
  ) {}

  async canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
    const user = await this.afAuth.auth.currentUser;
    const isLoggedIn = !!user;
    if (!isLoggedIn) {
      this.snack.authError();
    }
    return isLoggedIn;
  }
}

如果我登录到我的应用程序并通过单击链接重定向到路由,即/projects/1,一旦警卫检查完成,我就会成功定向,但是如果我手动将浏览器定向到相同的 URI,我会被踢回主页并告诉我未授权(通过我的零食服务,它将我重定向到登录页面并闪烁祝酒词说我需要登录)

如果我修改我的代码以引入一些人为的减速:

  async canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
    await this.timeout(300);
    const user = await this.afAuth.auth.currentUser;
    const isLoggedIn = !!user;
    console.log(this.afAuth.auth.currentUser);
    if (!isLoggedIn) {
      this.snack.authError();
    }
    return isLoggedIn;
  }
  timeout(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

然后我可以通过链接直接到路由或通过地址栏手动点击 URI,让我相信应用程序已经被引导和加载,但是在身份验证提供程序完成初始化之前检查身份验证保护,导致第一次进行空检查。

显然,我不想在每个页面上留下 300 毫秒的延迟,只是为了确保在没有经过身份验证的情况下无法导航到受保护的页面。在我检查currentUser属性之前,有什么方法可以订阅正在初始化的身份验证提供程序?

标签: angular

解决方案


我之前遇到过同样的问题,我的解决方法是返回一个 Observable 而不是 Promise 并像这样使用 rxjs 管道:

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable < boolean > {
  return from(this.afAuth.auth.currentUser).pipe(
    switchMap(user => {
      const isLoggedIn = !!user;
      if (!isLoggedIn) {
        this.snack.authError();
      }
      return isLoggedIn;
    })
  );
}

让我知道它是否有效


推荐阅读