Nestjs自定义注解实现接口权限控制详解

2022-12-07 08:45:32
目录
正文定义角色枚举声明自定义注册(装饰器)实现角色守卫 RolesGuard在 providers 中引入 RolesGuard使用注解

正文

当业务接口开发完成之后,正式上线之前还需要对每个接口进行权限控制。比如删除用户只能管理员角色操作,查询全部用户只有管理员有权限等。

对接口实现权限控制有很多种方案,最简单的实现是在每个接口的>

Nest 官方文档为我们提供了几种权限控制方式,我们来实现最基础的基于角色的 RBAC(Role-based access control) 控制方案。

实现 RBAC 权限控制一共需要五步:

    定义角色的枚举类 Role声明自定义注解(装饰器)roles.decorators.ts实现角色守卫 RolesGuard在 app.module.ts 的 providers 中引入 RolesGuard在需要的接口上添加注解:@Roles(Role.Admin, Role.SuperAdmin)�

    定义角色枚举

    梳理好系统中一共有多少种角色,并为每种角色确定好>

    export enum Role {
      SuperAdmin = 'SuperAdmin',
      Admin = 'Admin',
      Normal = 'Normal',
      Guest = 'Guest',
    }
    

    声明自定义注册(装饰器)

    新建一个>roles.decorator.ts文件,就可以在 Controller 中使用 @Roles注解了

    import { SetMetadata } from '@nestjs/common';
    import { Role } from '@constants';
    export const ROLES_KEY = 'roles';
    export const Roles = (...roles: Role[]) => SetMetadata(ROLES_KEY, roles);
    

    实现角色守卫>

    新建 roles.gurad.ts文件,它的作用是告诉 nest 什么情况下请求应该被拦截,什么情况下请求应该被通过。

    通过 reflector可以拿到注解中传入的角色 code 列表,通过 context.switchToHttp().getRequest()可以拿到 request 对象。因为我们使用了 jwt,在 JwtStrategy�中往 user 对象中写入了当前登录用户的角色信息,所以可以通过从 request 中取 user 的方式得到角色列表。这块具体的获取方式根据你的业务而定,业务中把角色信息放在了什么地方,就从哪里取。

    拿到注解中传入的角色,和用户已有的角色进行对比,如果用户角色中包含需要的角色,则返回 true,如果返回 false,则会抛出默认的异常如下:

    {
      "statusCode": 403,
      "message": "Forbidden resource",
      "error": "Forbidden"
    }
    

    我们需要定制错误信息,以使整个系统保持一致,则抛出一个自定义异常,这个异常按照统一规定的格式返回错误信息。

    import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
    import { Reflector } from '@nestjs/core';
    import { ROLES_KEY } from '../decorators/roles.decorator';
    import { Role } from '@constants';
    import { InternalErrorException } from '../../exception/InternalErrorException';
    import { errorResult } from '@utils';
    import { ErrorCodes } from '@constants/errorCode';
    @Injectable()
    export class RolesGuard implements CanActivate {
      constructor(private reflector: Reflector) {}
      canActivate(context: ExecutionContext): boolean {
        const requiredRoles = this.reflector.getAllAndOverride<Role[]>(ROLES_KEY, [
          context.getHandler(),
          context.getClass(),
        ]);
        if (!requiredRoles) {
          return true;
        }
        const { user } = context.switchToHttp().getRequest();
        const roleCodes = user.roles?.map((item) => item.code);
        const flag = requiredRoles.some((role) => roleCodes?.includes(role));
        if (!flag) {
          throw new InternalErrorException(errorResult(ErrorCodes.NoAuth));
        }
        return flag;
      }
    }
    

    在>

    如果想在全局使用自定义注解,就在 app.module.ts中全局引入。如果仅想在某个 controller 中使用,则在这个 controller 层级的 module 中声明。

    providers: [
      {
        provide: APP_GUARD,
        useClass: RolesGuard,
      },
    ],
    

    使用注解

    在接口上使用自定义注解实现权限校验。
    括号里可以写一个权限,也可以写多个,因为我们 roles.decorator.ts中写的参数类型为 Role[]

      @Get()
      @Roles(Role.Admin, Role.SuperAdmin)
      async findAll() {
        const users = await this.userService.findAll();
        return successResult(users);
      }
    

    至此,使用自定义注册实现接口权限控制就完成啦。

    以上就是Nestjs自定义注解实现接口权限控制详解的详细内容,更多关于Nestjs注解接口权限的资料请关注易采站长站其它相关文章!