扩展 Extensions

导读

警告

本章仅适用于代码优先方法。

扩展是一种高级、低级功能,可让您在类型配置中定义任意数据。将自定义元数据附加到某些字段允许您创建更复杂、更通用的解决方案。例如,使用扩展,您可以定义访问特定字段所需的字段级角色。此类角色可以在运行时反映出来,以确定调用者是否具有足够的权限来检索特定字段。

添加自定义元数据

要为字段附加自定义元数据,请使用从 @nestjs/graphql 包导出的 @Extensions() 装饰器。

ts
@Field()
@Extensions({ role: Role.ADMIN })
password: string;

在上面的示例中,我们为 role 元数据属性分配了 Role.ADMIN 的值。Role 是一个简单的 TypeScript 枚举,它将我们系统中可用的所有用户角色分组。

请注意,除了在字段上设置元数据之外,您还可以在类级别和方法级别(例如,在查询处理程序上)使用 @Extensions() 装饰器。

使用自定义元数据

利用自定义元数据的逻辑可以根据需要而变得复杂。例如,您可以创建一个简单的拦截器,用于存储/记录每个方法调用的事件,或者创建 字段中间件,将检索字段所需的角色与调用者权限(字段级权限系统)进行匹配。

为了说明目的,让我们定义一个 checkRoleMiddleware,将用户的角色(此处硬编码)与访问目标字段所需的角色进行比较:

ts
export const checkRoleMiddleware: FieldMiddleware = async (
  ctx: MiddlewareContext,
  next: NextFn,
) => {
  const { info } = ctx
  const { extensions } = info.parentType.getFields()[info.fieldName]

  /**
   * 在实际应用中,`userRole`变量应该代表调用者(用户)的角色(例如,`ctx.user.role`)。
   */
  const userRole = Role.USER
  if (userRole === extensions.role) {
    // or just "return null" to ignore
    throw new ForbiddenException(
      `User does not have sufficient permissions to access "${info.fieldName}" field.`,
    )
  }
  return next()
}

有了这个,我们可以为密码字段注册一个中间件,如下所示:

ts
@Field({ middleware: [checkRoleMiddleware] })
@Extensions({ role: Role.ADMIN })
password: string;