调用函数

时间:2019-07-31 13:15:36

标签: angular rxjs

我正在使用jwt令牌,我需要知道用户的角色,才能决定允许在客户端上进行哪个路由以及在导航栏中显示哪个菜单。

所有这些都保存在服务中,该服务应告知应用程序路由模块是否允许用户访问此路由,并告诉导航栏是否应显示菜单。

这是有效的现有解决方案:

security.service.ts

import { ApplicationRef, EventEmitter, Injectable, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from "rxjs";
import { ActivatedRouteSnapshot, RouterStateSnapshot } from "@angular/router";
import { LoggingUtil } from "../utils/logging.util";
import { ServerUtil } from "../utils/server.util";
import { UserRoleModel } from "../model/models-generated";
import { Log } from "@angular/core/testing/src/logger";

@Injectable({
  providedIn: 'root'
})
export class SecurityService {

  constructor(private client: HttpClient) {}

  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    if (next.data.permission.includes(SecurityService.AVA_PERMISSION)) {
      this.getUserRoles().subscribe((result) => {
        return of(result.hasAvaRole);
      });
    } else if (next.data.permission.includes(SecurityService.ADMIN_PERMISSION)) {
      this.getUserRoles().subscribe((result) => {
        return of(result.hasAdminRole);
      });
    } else if (next.data.permission.includes(SecurityService.USER_PERMISSION)) {
      this.getUserRoles().subscribe((result) => {
        return of(result.hasUserRole);
      });
    }
    return of(false);
  }



  public getUserRoles(): Observable<UserRoleModel> {
    let serverUrl = ServerUtil.GetRestApiURL() + '/role';
    return this.client.get<UserRoleModel>(serverUrl);
  }


navbar.component.ts

import {Component, OnInit} from '@angular/core';
import {SecurityService} from "../../services/security.service";
import {Observable} from "rxjs";


@Component({
  selector: 'app-navbar',
  templateUrl: "./navbar.component.html",
  styleUrls: ['./navbar.component.css']
})
export class NavbarComponent implements OnInit {
  isAdmin: boolean;

  constructor(private securityService: SecurityService) {}


  ngOnInit() { 
    this.securityService.getUserRoles().subscribe(value => {
      this.isAdmin = value.hasAdminRole;
    })
  }
}


此版本的问题在于,每条路线更改都会调用 canActivate(),因此也会调用 getUserRoles()

我的目标是这样做,您可以按照旧方式进行操作或存储值。切换是在弹簧轮廓的帮助下完成的,因此我将代码更改如下:

security.service.ts

export class SecurityService {
  hasAvaRole = false;
  hasAdminRole = false;
  hasUserRole = false;
  profiles: string[] = [];
  profileLoaded = false;

  // previously getUserRoles
  loadRoles(): Observable<UserRoleModel> {
    let serverUrl = ServerUtil.GetRestApiURL() + '/' + this.ACTION_PATH;
    LoggingUtil.debug("posting to remote server : " + serverUrl);
    return this.client.get<UserRoleModel>(serverUrl);
  }

  loadProfiles(): Observable<string[]> {
    let serverUrl = ServerUtil.GetRestApiURL() + '/' + this.PROFILE_PATH;
    LoggingUtil.debug("calling remote server : " + serverUrl);
    LoggingUtil.debug('client info :');
    console.log(this.client);
    return this.client.post<string[]>(serverUrl, null);
  }

  private getUserRolesSync(): UserRoleModel {
    return {'hasAvaRole': this.hasAvaRole, 'hasAdminRole': this.hasAdminRole, 'hasUserRole': this.hasUserRole}
  }


  getUserRoles(): Observable<UserRoleModel> {
     // if roles aren't in memory we load them
    if (!this.profileLoaded) {
      this.loadProfiles().subscribe((profiles: string[]) => {
        this.profiles = profiles;
        this.profileLoaded = true;
        if (this.profiles.includes('saving-role')) {
          this.loadRoles().subscribe(result => {
            this.hasAvaRole = result.hasAvaRole;
            this.hasAdminRole = result.hasAdminRole;
            this.hasUserRole = result.hasUserRole;
            return of(this.getUserRolesSync());
          });
        } else {
          return this.loadRoles();
        }
      });
    } else {
      if (this.profiles.includes('saving-role')) {
        return of(this.getUserRolesSync());
      } else {
        return this.loadRoles();
      }
    }

起初,我以为没有注入httpClient,但通过打印它,我发现情况并非如此。弹簧轮廓也已正确加载。

我现在在我订阅该函数的行上在navbar.component.ts中收到错误“无法读取未定义的属性'subscribe'”

1 个答案:

答案 0 :(得分:1)

问题在getUserRoles中。如果用户进入第一个if状态,则控件将进入subscribe块内。但是您还没有从那里退回任何东西。因此,您必须从那里return。而且,除了subscribe之外,您还必须pipeswitchMap将上下文切换到内部Observable:

getUserRoles(): Observable < UserRoleModel > {
  // if roles aren't in memory we load them
  if (!this.profileLoaded) {
    return this.loadProfiles().pipe(
      switchMap(profiles: string[]) => {
        this.profiles = profiles;
        this.profileLoaded = true;
        if (this.profiles.includes('saving-role')) {
          this.loadRoles().pipe(
            switchMap(result => {
              this.hasAvaRole = result.hasAvaRole;
              this.hasAdminRole = result.hasAdminRole;
              this.hasUserRole = result.hasUserRole;
              return of(this.getUserRolesSync());
            })
          );
        } else {
          return this.loadRoles();
        }
      })
    );
  }
  else {
    if (this.profiles.includes('saving-role')) {
      return of(this.getUserRolesSync());
    } else {
      return this.loadRoles();
    }
  }
}