Angular - 无法获取当前用户在 guard 中的角色以检查 he/she 是否有权访问受保护的路由

Angular - Cannot get current user's role in guard to check if the he/she has permission to access protected routes

我正在尝试在基于 Angular 的项目上实施 基于角色的访问控制 ,其中有多种类型的角色

我想在CanActivate接口中获取用户的数据(角色属性),以检查用户是否有权访问guard中受保护的routes,但是BehaviouralSubject 在收到来自 API 的最新值后不会更新初始状态。

因此我在身份验证服务中获取用户数据, 然后将收到的值传递给 userRole 主题,但更新 属性 (BehaviouralSubject) 在守卫文件中不可用。

身份验证服务

    constructor() {
      let localToken: string
      if (localStorage.getItem('token')) {
        localToken = localStorage.getItem('token')
        this.getUserInfo(localToken)
      }
    }
      userRole = new BehaviorSubject(null)
      userRole$ = this.userRole.asObservable()    

      // called in constructor of a auth. service (every time when user called) 
      // and after login as well, so user's data always available. 
      getUserInfo(data) {
          this.requestService
            .post('GET_USER_INFO', data)
            .subscribe((response: ILoggedInUser) => {
               // data from API {email: "test@test.com", userName: "ccc", role: "viewer"}
               this.userRole.next(response.user)  
            })
        }

Auth Guard

    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {

      return this.authService.userRole$.pipe(
        map(member => {
          if (member) {
            // check if route is restricted by role
            if (
              route.data.roles &&
              route.data.roles.indexOf(member.role) === -1
            ) {
              // role not authorised so redirect to home page
              this.router.navigate(['/login'])
              return false
            }

          return true
          } else {
            this.router.navigate(['/login'])
            return false
          }
        }),
      )
    }

这里是路由:

     const routes: Routes = [
      {
        path: 'home',
        component: HomeComponent,
      },
      {
        path: 'admin',
        component: AdminComponent,
        canActivate: [AuthGuard],
        data: { roles: ['admin'] },
      },
      {
        path: 'editor',
        component: EditorsComponent,
        canActivate: [AuthGuard],
        data: { roles: ['admin', 'editor'}
      },
      {
        path: 'viewer',
        component: ViewersComponent,
        canActivate: [AuthGuard],
        data: { roles: ['admin', 'viewer'] },
      }
    ]

我也尝试了另一种方法,(例如使用订阅)但是当我尝试 subscribeuserRole 这样的主题时:

     return this.authService.userRole.subscribe((member) => {
        .......
        ....... 
     }

然后有一个 属性 'canActivate' in type 'AuthGuard' is not assignable to the same 属性 in base type 'CanActivate' 错误, 因为 Subscription 类型不能分配给类型 boolean.

因此,您能否给出任何提示或推荐使用可观察对象处理 angular 中的 RBAC 的更好方法。

P.S.

我看到 solutionslocalStorage,但我不想在那里保留用户数据(令牌除外)。

问题是 userRole$ observable emmits null 最初是因为它订阅了 userRole BehaviorSubject,它获取 null 作为参数。

因此,userRole$ observable 等于 null 得到更新,属性 canActivate in type AuthGuard cannot return null.

因此,您应该在将对象传递给映射之前使用 filter() 运算符,以消除空值。

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
  return this.authService.userRole$.pipe(
    filter(member => !!member),  // Filter NULL value here before sending object further
        map(member => {
        ....
      return true

      } else {
        ....
      }
    )
}