【问题标题】:Angular - How to avoid multiple http calls in canActivateAngular - 如何避免 canActivate 中的多个 http 调用
【发布时间】:2021-02-01 16:50:40
【问题描述】:

我有一个带有两个 authGuard 服务的 Angular 应用程序:

export class AuthGuardService implements CanActivate {
  constructor(public auth: AccountService, public router: Router) {}
  canActivate(): Observable<boolean> {
    return this.auth.identity().pipe(
      map(account => {
        if (account) {
          return true;
        }
        this.router.navigate(['welcome']);
        return false;
      })
    );
  }
}

@Injectable()
export class StartupService implements CanActivate {
  isAdmin: boolean;
  constructor(public auth: AccountService, public router: Router, private sidebarService: SidebarService) {}
  canActivate(): Observable<boolean> {
    return this.auth.identity().pipe(
      switchMap(account => {
        this.isAdmin = account.isAdmin;
        return this.sidebarService.getCompanies(account.id.toString());
      }),
      map(firms => {
        if(this.isAdmin && Object.keys(firms).length === 0) {
          this.router.navigate(['startup']);
          return false;
        }
          return true;
      }),
      catchError(() => of(false))
    );
  }
}

在 AuthGuardService 中,我调用身份服务来检查我是否已登录,如果没有,我需要重定向到欢迎页面;在 StartupService 我调用相同的服务,我还检查我是否是管理员并且我有一些可用的数据(公司)。我还在 AppComponent 的 ngOnInit 中调用相同的服务,并使用 ngrx 将帐户状态保存在商店中。我调用相同的服务 3 次。避免这种情况的最佳方法是什么?我在哪里可以使用 ngrx 选择器?我在调试中看到 canActivate 在 ngOnInit AppComponent 之前被调用。有什么建议吗?

【问题讨论】:

    标签: angular typescript


    【解决方案1】:
    export class AuthGuardService implements CanActivate {
      constructor(
        public auth: AccountService
        public router: Router
      ) {}
    
      canActivate(): Observable<boolean> {
        return this.auth.identity().pipe(
          map(account => {
            if (account) {
              return true;
            }
            this.router.navigate(['welcome']);
            return false;
          })
        );
      }
    }
    
    @Injectable()
    export class StartupService implements CanActivate {
      constructor(
        private auth: AccountService,
        private router: Router,
        private sidebarService: SidebarService
      ) {}
    
      canActivate(): Observable<boolean> {
        return this.auth.identity().pipe(
          switchMap(account => this.sidebarService.getCompanies(account.id.toString())
            .pipe(
              map(firms => {
                if(account.isAdmin && Object.keys(firms).length === 0) {
                  this.router.navigate(['startup']);
                  return false;
                }
                return true;
              }),
              catchError(() => of(false)) // you probably also want some redirection on error
            )
          ),
        );
      }
    }
    

    在你的设置中更重要的是你如何实现AccountService.identity 如果它返回一些具有当前用户身份状态的可观察对象,如下所示:

    class AccountService {
      identity$ = new ReplaySubject(1);
    
      identity() {
        return this.identity$;
      }
    
      authenticate() {
        this.http.post('/authentication').subscribe((identity) => {
          this.identity$.next(identity)
        })
      }
    
      logout() {
        this.identity$.next(null)
      }
    }
    

    只有当你调用身份验证时它才会调用HTTP,并且你的用户身份将存储在identity$

    【讨论】:

    • 太好了!但是这样在 canActivate 中我可以只使用返回我可观察的身份的身份函数吗?
    • @Andy88 是的,但您可以更进一步,将 canActive 中的所有逻辑隐藏在某些访问控制服务“canAccessResource”方法后面,并在您想要重定向时对其结果做出反应
    猜你喜欢
    • 2021-09-13
    • 2016-01-05
    • 2023-04-11
    • 1970-01-01
    • 1970-01-01
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多