首页 > 解决方案 > Angular - 无法获取当前用户在警卫中的角色以检查他/她是否有权访问受保护的路线

问题描述

我正在尝试在有多种角色的基于项目的基础上实施基于角色的访问控制Angular

我想在CanActivate界面中获取用户的数据(角色属性)以检查用户是否有权访问受保护routes的 in guard,但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)  
            })
        }

认证卫士

    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) => {
        .......
        ....... 
     }

那么 “AuthGuard”类型中的属性“canActivate”不可分配给基类型“CanActivate”错误中的同一属性,因为Subscription类型不可分配给类型boolean

因此,您能否给出任何提示或推荐使用 observables处理RBAC的更好方法。angular

附言

我已经看到了解决方案localStorage但我不想将用户的数据(令牌除外)保留在那里。

标签: angularobservablerbacbehaviorsubjectangular-guards

解决方案


问题是userRole$observablenull最初会发出,因为它订阅了 userRole BehaviorSubject,它作为参数获取 null 。

因此,userRole$ observable 等于 null 获取更新,并且类型 AuthGuard 中的属性 canActivate 不能返回 null。

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

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 {
        ....
      }
    )
}

推荐阅读