You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CASL进行权限校验时抛出运行时错误的问题求助

CASL规则嵌套对象查询触发TypeScript错误:"equals"不支持数组和对象比较

问题描述

我在中间件中配置CASL权限规则,目的是允许已认证用户访问同一公寓(unitId)下的其他用户,规则代码如下:

can(DirectoryAction.VIEW, 'DirectoryUser', { roles: { some: { role: { unitId: CASL_ROLE.unitId } } } });

其中:

  • DirectoryAction是包含view、delete等操作的枚举
  • DirectoryUser是目标对象名称
  • CASL_ROLE指代已认证用户的角色信息
  • unitId是公寓ID

代码编译无异常,但VS Code检测到TypeScript运行时错误:

"equals" does not supports comparison of arrays and objects

对应的Prisma模型定义如下:

model DirectoryUser {
    id          BigInt   @id @default(autoincrement())
    userName    String   @map("user_name")
    password    String
    roles   DirectoryRoleUserMapping[]

    @@map("directory_users")
}

model DirectoryRoleUserMapping {
    id  BigInt          @id @default(autoincrement())
    roleId  BigInt          @map("role_id")
    role    DirectoryRole   @relation(fields: [roleId], references: [id], onDelete: Cascade, onUpdate: Cascade)
    userId  BigInt      @map("user_id")
    user    DirectoryUser   @relation(fields: [userId], references: [id], onDelete: Cascade, onUpdate: Cascade)

    @@unique([roleId, userId])
    @@map("directory_role_user_mappings")
}

model DirectoryRole {
    id     BigInt    @id @default(autoincrement())
    name   String
    unitId BigInt?   @map("unit_id")
    unit   BmsUnit?  @relation(fields: [unitId], references: [id], onDelete: Cascade, onUpdate: Cascade)
    rank   BigInt

    users  DirectoryRoleUserMapping[]

    @@unique([name, unitId])
    @@map("directory_roles")
}

如果简化条件为{ roles: { some: { roleId: CASL_ROLE.id } } }则无错误,但这不符合业务需求。我发现只要在some中使用嵌套对象而非简单键值对就会触发该错误,求排查解决。

问题根源

CASL默认会将{ role: { unitId: CASL_ROLE.unitId } }解析为整个role对象等于{ unitId: CASL_ROLE.unitId },而非role对象的unitId字段等于目标值。这种对象级别的比较会触发Prisma的equals操作,但Prisma不支持用equals直接比较对象/数组,因此抛出错误。

解决方法

方法1:显式指定字段比较操作符

通过显式使用Prisma的字段比较语法,明确告诉CASL要比较的是role对象下的unitId字段,而非整个对象:

can(DirectoryAction.VIEW, 'DirectoryUser', {
  roles: {
    some: {
      role: {
        unitId: { equals: CASL_ROLE.unitId }
      }
    }
  }
});

方法2:使用函数式规则(更灵活)

如果嵌套查询的类型推断仍有问题,可以改用CASL的函数式规则,直接返回符合Prisma语法的查询条件,绕开类型推断限制:

can(DirectoryAction.VIEW, 'DirectoryUser', (_, { user }) => {
  const targetUnitId = user.CASL_ROLE.unitId;
  return {
    roles: {
      some: {
        role: {
          unitId: targetUnitId
        }
      }
    }
  };
});

方法3:检查CASL与Prisma适配器版本

确保你使用的@casl/prisma适配器版本与Prisma版本兼容,旧版本的适配器可能对嵌套查询的类型支持不完善。可以尝试升级到最新稳定版:

npm update @casl/prisma prisma

验证

修改后,TypeScript错误应该消失,同时权限规则会正确匹配同一unitId下的用户:只要当前用户的角色所属公寓ID,与目标用户的任意角色所属公寓ID一致,就允许访问。

内容的提问来源于stack exchange,提问作者Anne Nonyme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 15:43:29