授权

授权规则涵盖了生成的 Cypher 查询允许访问哪些特定数据。它们使用谓词来评估从 GraphQL 查询生成的 Cypher 访问的数据,从而允许或不允许在节点及其属性的上下文中执行。

所有授权规则都隐含地需要身份验证,因为规则通常针对 JWT 负载中的值进行评估。

在显式身份验证的情况下,使用 @authentication 指令配置,它仅在 Cypher 转换时进行评估。需要身份验证的查询的未经身份验证的请求永远不会到达数据库。

@authorization 指令不适用于订阅,它仅适用于查询和变异。相反,如果打算在 API 中使用订阅并希望保护事件,请使用 @subscriptionsAuthorization 配置订阅的授权。

规则

过滤

过滤规则会过滤掉用户无权访问的数据,而不会引发任何错误。这些规则被转换为过滤谓词,这些谓词针对数据库中匹配的数据进行评估。

过滤规则不仅保护数据,还向未经授权的用户隐藏该数据存在的信息。

例如,以下是如何过滤掉不属于当前 UserPost 节点

type User {
    id: ID!
}

type Post @authorization(filter: [
    { where: { node: { author: { id: "$jwt.sub" } } } }
]) {
    title: String!
    content: String!
    author: User! @relationship(type: "AUTHORED", direction: IN)
}

操作

可以将过滤配置为仅在某些操作上执行

  • 读取

  • 聚合

  • 更新

  • 删除

  • 创建关系

  • 删除关系

例如,仅要求对读取和聚合帖子进行过滤

type Post @authorization(filter: [
    { operations: [READ, AGGREGATE] where: { node: { author: { id: "$jwt.sub" } } } }
]) {
    title: String!
    content: String!
    author: User! @relationship(type: "AUTHORED", direction: IN)
}

如果 operations 参数没有包含操作列表,则 GraphQL 库会将授权配置视为已提供完整操作列表。

验证

如果对用户无权访问的数据执行查询,则验证规则会引发错误。这些规则通过包含对 apoc.util.validatePredicate 的调用的过滤谓词在数据库中进行评估。

例如,以下是如何在用户以外的任何人访问 User 时引发错误,除非该用户是用户本身或管理员

type JWT @jwt {
    roles: [String!]!
}

type User @authorization(validate: [
    { where: { node: { id: "$jwt.sub" } } }
    { where: { jwt: { roles_INCLUDES: "admin" } } }
]) {
    id: ID!
}

操作

可以将验证配置为仅在某些操作上执行

  • 读取

  • 聚合

  • 创建

  • 更新

  • 删除

  • 创建关系

  • 删除关系

例如,仅要求对帖子的更新或删除进行验证

type Post @authorization(validate: [
    { operations: [UPDATE, DELETE] where: { node: { author: { id: "$jwt.sub" } } } }
]) {
    title: String!
    content: String!
    author: User! @relationship(type: "AUTHORED", direction: IN)
}

如果 operations 参数没有包含操作列表,则 GraphQL 库会将授权配置视为已提供完整操作列表。

无需身份验证的授权

默认情况下,每个授权检查都隐式需要身份验证,但可以在每个规则的基础上禁用此功能。例如,当节点具有一个属性来标记该节点是否应为公共节点时,可能会出现这种情况。

例如,在某些 Post 节点是私有的并且属于特定的 User,而其他 Post 节点是公开的并且任何用户都可以读取的情况下,以下是如何设置此内容

type User {
    id: ID!
}

type Post @authorization(filter: [
    { where: { node: { author: { id: "$jwt.sub" } } } }
    { requireAuthentication: false, operations: [READ], where: { node: { public: true } } }
]) {
    title: String!
    content: String!
    public: Boolean!
    author: User! @relationship(type: "AUTHORED", direction: IN)
}