【问题标题】:Difficulties in making right Angular`s guard制作正确的 Angular 后卫的困难
【发布时间】:2019-09-10 18:44:13
【问题描述】:

我的任务很简单,就是可以,但我不明白为什么它不能很好地工作。 我尝试制作一个保护路线,以保护除具有“管理员”角色的用户之外的所有用户。

如何检查?我使用用户 api_token 向我的 api 服务器发送请求,服务器检查令牌,并向我发送带有“true”(具有角色)或 false 的响应。 在这部分中,一切都完美无缺。 当我尝试完全在警卫中使用此响应时出现问题

这里有我的服务代码和我的警卫。 第一个:

    isAdmin(apiToken: string): Observable<string> {
    const params = new FormData();
    params.append('api_token', apiToken);
    return this.http.post(this.urlConfig.IS_ADMIN, params)
      .pipe(map(resp => ResultResponse.fromJson(resp)))
      .pipe(map(ResResp => ResResp.response));
  }

后卫:

admin = false;
token;

constructor(private httpAuthService: HttpAuthService,
              @Inject(MessagesService) private msgService: MessagesService, private pRouter: Router) {
  }

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | boolean | UrlTree {
    if (localStorage.length > 0) {
      const data = JSON.parse(localStorage.getItem('tokenData'));
      this.token = data.api_token;
    }
    if (this.token) {
      this.isAdmin();
      if (this.admin) {
        return true;
      }
      this.redirectAndLogin();
    }
    this.redirectAndLogin();
  }

  private redirectAndLogin() {
    this.msgService.loginWindowShow();
    this.Router.navigate(['/main']);
    return false;
  }

  private isAdmin() { 
    this.httpAuthService.isAdmin(this.token).subscribe(r => {
      this.admin = r === 'true';
    });
  }

在服务的情况下,它发送到守卫“真”或“假”,是字符串类型,但它工作得很好。 但管理属性仍然为假,isAdmin 方法不会将此属性更改为“真”。并且一直守卫将我重定向到登录表单。 为什么会这样?

【问题讨论】:

  • 在浏览器中应用检查并调试一次。
  • 问题是您使用异步代码同时尝试使用不起作用的回调同步进行检查。您可以返回 ObservablePromise 以保护您的异步检查,并且只有在此之后您才能处理您的流程。

标签: angular guard


【解决方案1】:

问题是您试图在 isAdmin() 函数中分配 this.admin 值,但您不知道它何时被预先分配给 admin 属性,因为它的异步代码。

解决方案很简单,只需使用订阅来执行映射,将值转换为布尔值,然后使用制表符进行重定向。

像这样:

private isAdmin() { 
  return this.httpAuthService.isAdmin(this.token).pipe(map(r => r === 'true'));
}

可以激活功能:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): 
  Observable<boolean | UrlTree> | boolean | UrlTree {
  if (localStorage.length > 0) {
    const data = JSON.parse(localStorage.getItem('tokenData'));
    this.token = data.api_token;
  }
  this.isAdmin()
    .pipe(tab(r => {
       if(!r) {
         this.redirectAndLogin();
       }
    });
}

【讨论】:

  • 非常感谢。你的解决方案不能正常工作(我不知道为什么,“点击”什么也没给我)但给我一些提示,我解决了我的问题。
【解决方案2】:

谢谢,你说的很对。让我回到您的解决方案,它不起作用,我做错了什么?

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | boolean | UrlTree {
    if (localStorage.length > 0) {
      const data = JSON.parse(localStorage.getItem('tokenData'));
      this.token = data.api_token;
    }
    if (this.token) {
      this.isAdmin()
        .pipe(tap(r => {
          console.log(r); 
// In this line console.log shows me nothing, as i see, "pipe" doesnt work properly, why it happens?
          if (!r) {
            this.redirectAndLogin();
          }
        }));
      return true;
    }
    this.redirectAndLogin();
  }

private isAdmin(): Observable<boolean> {
    return this.httpAuthService.isAdmin(this.token).pipe(map(r => r === 'true'));
  }

我又在服务中回复了我的方法,也许麻烦从这里开始:

isAdmin(apiToken: string): Observable<string> {
    const params = new FormData();
    params.append('api_token', apiToken);
    return this.http.post(this.urlConfig.IS_ADMIN, params)
      .pipe(map(resp => ResultResponse.fromJson(resp)))
      .pipe(map(ResResp => ResResp.response));
  }

【讨论】:

    【解决方案3】:

    非常感谢所有答案。我简化了我的守卫,它起作用了。答案如下:

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | boolean | UrlTree {
        if (localStorage.length > 0) {
          const data = JSON.parse(localStorage.getItem('tokenData'));
          this.token = data.api_token;
        }
        if (this.token) {
          this.httpAuthService.isAdmin(this.token).subscribe(r => {
            if (!r) { this.redirectAndLogin(); }
          });
          return true;
        }
        this.redirectAndLogin();
      }
    
      private redirectAndLogin() {
        this.msgService.loginWindowShow();
        this.Router.navigate(['/main']);
        return false;
      }
    

    【讨论】:

    • 您好,我希望看到您解决了它,但是您使用的做法并不好,我会给您举个例子,为什么这是一个不好的做法。在您知道是否是管理员之前,您让用户进入 roote。一旦你订阅了一些东西,你就使用了异步代码,这意味着你不知道订阅中的代码什么时候会被执行。这正是我使用制表符运算符的原因。示例:stackblitz.com/edit/angular-amfvkf
    • 好的,谢谢,我知道我的错在哪里。但我不明白,没有 .subscribe 如何获得 HttpClient 答案? “在您对该方法返回的可观察对象调用 subscribe() 之前,HttpClient 方法不会开始其 HTTP 请求” - angular.io 也这么说 =)
    • 当您从 CanActivate 返回 Observable 时,它将自动为您订阅。只需将 HTTP 客户端返回的内容映射为布尔值。
    猜你喜欢
    • 1970-01-01
    • 2012-03-27
    • 2021-04-06
    • 1970-01-01
    • 2018-06-26
    • 1970-01-01
    • 2018-02-23
    • 1970-01-01
    • 2019-07-16
    相关资源
    最近更新 更多