nestjs-RBAC权限控制

653 阅读1分钟

nestjs-RBAC权限控制

  1. 创建表
  • 如果有菜单、资源等,需要创建菜单表 menus 与权限的映射表 roles_menus

role

  1. 创建枚举
export enum Role {
  User = 2,
  Admin = 1
}
  1. 创建装饰器

  • SetMetadata 可以将枚举 Role 的内容缓存,相当于 pinio
import { SetMetadata } from '@nestjs/common'
import { Role } from 'src/enum/roles.enum'

export const ROLES_KEY = 'roles'

// 装饰器Roles SetMetadata将装饰器的值缓存
export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles)
  1. 创建守卫

nest g gu guards/role --no-spec
  • req 中获取 req.user.username 需要配合 nestjsjwt 的守卫(经过后会从 token 中解析出 user 的值放到 req.user 中),如下,
@UseGuards(JwtGuard, RoleGuard)
import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'
import { Reflector } from '@nestjs/core'
import { ROLES_KEY } from 'src/decorators/roles.decorator'
import { Role } from 'src/enum/roles.enum'
import { UserService } from 'src/user/user.service'

@Injectable()
export class RoleGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private readonly userService: UserService
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 1.通过反射获取到装饰器的权限
    // getAllAndOverride读取路由上的metadata getAllAndMerge合并路由上的metadata
    const requireRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
      context.getHandler(),
      context.getClass()
    ])

    // 2.获取req拿到鉴权后的用户数据
    const req = context.switchToHttp().getRequest()

    // 3.通过用户数据从数据查询权限
    const user = await this.userService.findOneByName(req.user.username)
    const roleIds = user.roles.map((item) => item.id)

    // 4.判断用户权限是否为装饰器的权限 的some返回boolean
    const flag = requireRoles.some((role) => roleIds.includes(role))

    return flag
  }
}
  1. controller 使用
  • 方法的 @Roles 注解会覆盖控制器的注解
...

@Controller('roles')
@Roles(Role.Admin) // 装饰器会缓存Role.Admin的值 RoleGuard中获取缓存的值进行守卫鉴权
@UseGuards(JwtGuard, RoleGuard)
export class RolesController {
  constructor(private readonly rolesService: RolesService) {}

  ...

  @Get(':id')
  @Roles(Role.User)
  findOne(@Param('id') id: string) {
    return this.rolesService.findOne(+id)
  }

  ...
}