【问题标题】:How to wait for server authorization in an Angular role guard?如何在 Angular 角色守卫中等待服务器授权?
【发布时间】:2020-07-20 12:37:24
【问题描述】:

在我的应用程序中,用户登录并接收到 JWT,该 JWT 存储在本地存储中。用户通过身份验证后,会对服务器进行以下调用,以确定用户的角色和功能(他们可以访问哪些页面)。

我的问题是当用户想要打开一个页面(恢复旧会话、复制标签、将 URL 传递给其他人等)时,应用程序没有授权详细信息,必须首先请求它们,角色守卫启动。这会导致用户被重定向到登录页面。

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

  constructor(public auth: AuthService, public router: Router, public globalConfig: GlobalConfigService) { }

  canActivate(route: ActivatedRouteSnapshot): boolean {

    if (!this.auth.isAuthenticated()) {
      this.router.navigate(['login']);
      return false;
    }

    const expectedFunction = route.data.expectedFunction;

    if (!this.globalConfig.hasFunction(expectedFunction)) {
      this.router.navigate(['login']);
      return false;
    }

    return true;
  }
}

期望的函数在路由中定义,例如:

{
    path: 'system-admin', loadChildren: () => SystemAdminModule,
    data: { breadcrumb: 'System Admin', expectedFunction: FunctionType.SystemAdministration }, canActivate: [RoleGuard]
},

GlobalConfigService 中的 hasFunction 正文如下所示:

private authorizedUser: AuthorizedUser = new AuthorizedUser();

public hasFunction(expectedFunction: FunctionType): boolean {
    return !!this.authorizedUser.functions
            && this.authorizedUser.functions.find(f => f === expectedFunction) !== undefined;
}

AuthService 中完成的授权如下:

public onAuthorized = new Subject<AuthorizedUser>();

authorize() {
    const url = environment.APIURL + 'auth/currentuser';

    return this.http.get(url).subscribe(
        resp => {
            this.globalConfig.AuthorizedUser = resp;
            this.onAuthorized.next(resp as AuthorizedUser);
        }
    );
}

authorize() 是从AppComponent 中的ngOnInit() 调用的

ngOnInit(): void {
    if (this.auth.isAuthenticated()) {
      this.auth.authorize();
    } else {
      this.router.navigate(['login']);
    }
}

我相信解决方案是在用户通过身份验证时设置一些等待条件,然后在评估其他任何内容之前允许完成授权。这需要仅在RoleGuard 中发生,还是会跨越整个身份验证/授权过程?

【问题讨论】:

  • 路由器守卫能够“等待”。你只需要返回一个 observable,它会在稍后解析为 true/false。在那之前什么都不会发生

标签: angular typescript authorization angular-guards


【解决方案1】:

是的,您可以等待用户在您的守卫内进行授权。您需要记住的唯一一件事是不要两次授权用户,这意味着您应该在页面导航之间缓存授权结果。

role-guard.service.ts

canActivate(route: ActivatedRouteSnapshot): boolean | Promise<boolean> {

  if (!this.auth.isAuthenticated()) {
    this.router.navigate(['login']);
    return false;
  }

  return this.auth.authorize().then(result => {
    if (!result) {
      return false;
    }

    const expectedFunction = route.data.expectedFunction;

    if (!this.globalConfig.hasFunction(expectedFunction)) {
      this.router.navigate(['login']);
      return false;
    }

    return true;
  });
}

auth.service.ts

@Injectable({
  providedIn: 'root',
})
class AuthService {
  ...

  private authorizePromise: Promise<boolean>;

  constructor(private http: HttpClient, private globalConfig: GlobalConfigService) {}

  authorize(): Promise<boolean> {
    if (!this.authorizePromise) {
      const url = environment.APIURL + 'auth/currentuser';
      this.authorizePromise = this.http.get(url)
        .toPromise()
        .then(resp => {
          this.globalConfig.AuthorizedUser = resp;
          this.onAuthorized.next(resp as AuthorizedUser);
          return true;
        })
        .catch(() => false);
    }

    return this.authorizePromise;
  }
}

如您所见,我在 AuthService 中使用缓存的authorizePromise 来缓存授权结果,这样授权只会发生一次。

live example

中还有一些sn-ps

【讨论】:

    猜你喜欢
    • 2017-11-11
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    • 2019-11-30
    • 1970-01-01
    • 1970-01-01
    • 2016-04-20
    • 2018-01-10
    相关资源
    最近更新 更多