【问题标题】:Angular/rxjs: check Auth Data in Guard after page reload/refreshAngular/rxjs:页面重新加载/刷新后检查 Guard 中的身份验证数据
【发布时间】:2022-01-27 18:55:32
【问题描述】:

有一个身份验证服务,在身份验证后立即获取数据:

export class AuthService {

  profile: BehaviorSubject<Profile| undefined> = new BehaviorSubject<Profile| undefined>(undefined);

  constructor(private auth: Auth, private http: HttpHandlerService) {

    //login and fetch profile data
    this.auth.isAuth.subscribe(isAuth => {
      if (isAuth) { 
        this.http.getProfile.subscribe(profile => this.profile.next(profile))
      } 
    });
  }
}

应用程序全局需要配置文件数据(在标题等中)。

问题: 在页面刷新/页面重新加载时,我的 Guard 不会等待 Authsevice 完成,因此我无法访问我的配置文件数据。

似乎唯一可行的解​​决方案是将数据获取逻辑移到 Guard 中,请参阅AuthGuard doesn't wait for authentication to finish before checking user

但是,就我而言,这还不够。我需要全局的个人资料数据,如果我在受保护的路线上,它不仅会被获取。

所以我要做的就是确保在守卫工作之前获取我的数据。

我目前的解决方案:

export class ProfileGuard {

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

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.auth.profile.pipe(
      skipWhile(profile => !profile),
      tap(profile=> {
        if (profile && profile.banned) {
          this.router.navigate(['/banned']).then();
        }
      }),
      take(1),
      map(() => true)
    );
  }

我有两个问题:1)我需要将这个额外的逻辑添加到我所有的守卫中! 2)这个解决方案感觉很hacky。

真的没有更简单/更好的方法可以在刷新/页面加载后立即在 Guard 中检查我的个人资料数据吗?

【问题讨论】:

  • 什么意思“在页面刷新/页面重新加载时,我的 Guard 不会等待 Authsevice 完成,因此我无法访问我在 Guard 中的个人资料数据。”?服务没有初始化?顺便说一句,您是否有意使用skipWhile 而不是filter?您的代码将允许未定义/虚假值通过 if 您曾经获得一个通过 skipWhile 条件的值,但 filter 不会。
  • 嗯我将如何初始化服务?我的意思是我在 isAuth 变为 true 后立即获取数据。在页面刷新时,这可能需要一点时间,我的守卫不会等待。
  • 啊,关于 skip 虽然它没有区别,因为 take(1) 会发出收到的第一个值。这个想法是简单地等到身份验证配置文件返回一个有效值。
  • 好吧,如果您使用take,您是正确的,我没有考虑这一点,很好。否则,您的代码应该可以正常工作,我制作了一个小的Stackblitz example,它的工作方式相同,没有问题。您确定该服务之前没有发出任何内容。至于您最初的问题是否有更好的方法,请查看this question

标签: angular typescript rxjs angular2-routing angular-router-guards


【解决方案1】:

问题是您有 2 个请求(身份验证和获取配置文件),并且您希望它们同步工作,但它们是异步的。

  1. 避免在订阅中进行订阅。这是不良行为和问题的根源。
  2. 在管道中使用 switchMap(或 concatMap,如果您需要保持 isAuth Observable 处于活动状态,或任何其他合并运算符)让请求一个接一个地工作
export class AuthService {

  profile: BehaviorSubject<Profile| undefined> = new BehaviorSubject<Profile| undefined>(undefined);

  constructor(private auth: Auth, private http: HttpHandlerService) {

    //login and fetch profile data
    this.auth.isAuth.pipe(
     switchMap(isAuth => {
      if (isAuth) return this.http.getProfile;
      return of(undefined)
     }))
     .subscribe(profile => {
       if (profile) { 
         this.profile.next(profile))
       } else {
        // do whatever you want if user is not authorized
       }
     });
  }
}

【讨论】:

    猜你喜欢
    • 2014-10-30
    • 2016-08-13
    • 2018-02-17
    • 2012-08-14
    • 2018-08-20
    • 1970-01-01
    • 2020-06-26
    • 2015-06-25
    • 1970-01-01
    相关资源
    最近更新 更多