授权
|
这是 GraphQL Library 7 版本的文档。对于长期支持 (LTS) 版本 5,请参考 GraphQL Library 5 LTS 版本。 |
授权规则涵盖了生成的 Cypher 查询允许访问的具体数据。它们使用谓词来评估由 GraphQL 查询生成的 Cypher 所访问的数据,从而在节点及其属性的上下文中允许或禁止执行。
所有授权规则都隐含了对身份验证的要求,因为这些规则通常是根据 JWT 载荷中的值进行评估的。
在使用 @authentication 指令配置的显式身份验证情况下,它仅在 Cypher 转换时进行评估。如果查询需要身份验证但请求未经过身份验证,则该请求永远不会到达数据库。
|
|
过滤规则
过滤规则会过滤掉用户无权访问的数据,且不会抛出任何错误。这些规则被转换为过滤谓词,并根据数据库中匹配到的数据进行评估。
此类规则的过滤器工作方式与查询和聚合的过滤器完全相同。请参阅 过滤 (Filtering)。
过滤规则不仅保护数据,还向未经授权的用户掩盖了该数据是否存在的信息。
例如,以下是如何过滤掉不属于当前 User 的 Post 节点:
type User @node {
id: ID!
}
type Post @node @authorization(filter: [
{ where: { node: { authors: { some: { id: { eq: "$jwt.sub" } } } } } }
]) {
title: String!
content: String!
authors: [User!]! @relationship(type: "AUTHORED", direction: IN)
}
操作
可以配置过滤仅在某些操作上执行
-
读取 (READ) -
AGGREGATE(聚合) -
UPDATE(更新) -
DELETE -
CREATE_RELATIONSHIP(创建关系) -
DELETE_RELATIONSHIP(删除关系)
例如,仅对读取和聚合文章(post)要求过滤:
type Post @node @authorization(filter: [
{ operations: [READ, AGGREGATE], where: { node: { author: { id: { eq: "$jwt.sub" } } } } }
]) {
title: String!
content: String!
authors: [User!]! @relationship(type: "AUTHORED", direction: IN)
}
|
如果没有包含操作列表的 |
验证规则
如果针对用户无权访问的数据执行查询,验证规则会抛出错误。这些规则通过包含对 apoc.util.validatePredicate 调用的过滤谓词在数据库中进行评估。
例如,以下是如何在除用户本人或管理员之外的任何人访问 User 时抛出错误:
type JWT @jwt {
roles: [String!]!
}
type User @node @authorization(validate: [
{ where: { node: { id: { eq: "$jwt.sub" } } } }
{ where: { jwt: { roles: { includes: "admin" } } } }
]) {
id: ID!
}
操作
可以配置验证仅在某些操作上执行
-
读取 (READ) -
AGGREGATE(聚合) -
CREATE -
UPDATE(更新) -
DELETE -
CREATE_RELATIONSHIP(创建关系) -
DELETE_RELATIONSHIP(删除关系)
例如,仅在更新或删除文章时要求验证:
type Post @node @authorization(validate: [
{
operations: [UPDATE, DELETE]
where: { node: { authors: { some: { id: { eq: "$jwt.sub" } } } } }
}
]) {
title: String!
content: String!
authors: [User!]! @relationship(type: "AUTHORED", direction: IN)
}
|
如果没有包含操作列表的 |
何时执行 (When)
可以配置验证仅在操作执行之前或之后进行。这是通过使用 when 参数完成的,该参数接受以下值的数组:
-
BEFORE(之前) -
AFTER(之后)
此外,某些操作仅支持在之前或之后进行验证,下表对此进行了总结:
操作 (operation) |
when |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
例如,假设您希望允许某人更新文章。如果您想在更新后检查文章作者是否仍然是当前用户,请执行以下操作:
type Post @node @authorization(validate: [
{ operations: [UPDATE], when: [AFTER], where: { node: { author: { id: { eq: "$jwt.sub" } } } } }
]) {
title: String!
content: String!
author: User! @relationship(type: "AUTHORED", direction: IN)
}
字段授权
@authorization 指令既可以用在对象类型上,也可以用在它们的字段上,本页之前的示例大部分使用的是前者。当应用于字段时,授权规则仅在对该字段执行匹配操作时才会被评估。例如,考虑一个带有 password 字段的 User 类型:
type User @node {
id: ID!
username: String!
password: String! @authorization(validate: [{ operations: [READ, UPDATE], where: { node: { id: { eq: "$jwt.sub" } } } }])
}
执行以下查询时,不需要有效的身份:
{
users {
username
}
}
然而,考虑以下查询:
{
users {
username
password
}
}
这将要求请求中提供有效的 JWT,并且匹配的用户将根据 JWT 主题(subject)进行过滤。这也适用于尝试更新 password 字段的情况,更新将仅应用于与 JWT 匹配的用户。
无身份验证的授权
默认情况下,每个授权检查都隐式要求身份验证,但可以针对每个规则禁用此要求。例如,当节点具有标记该节点是否应公开的属性时,可能就是这种情况。
例如,如果某些 Post 节点是私有的且属于特定的 User,而其他 Post 节点是公开的且任何用户均可读取,以下是设置方法:
type User @node {
id: ID!
}
type Post @node @authorization(filter: [
{
requireAuthentication: false,
operations: [READ],
where: { node: { public: { eq: true } } }
}
]) {
title: String!
content: String!
public: Boolean!
authors: [User!]! @relationship(type: "AUTHORED", direction: IN)
}
规则排序
在每个规则集(filter 和 validate)中,规则通过 OR 连接。这两个规则集之间通过 AND 连接。
例如,以下规则允许在 JWT 角色声明包含 admin 或者节点上的 locked 属性为 false 时更新 User 节点:
type User @node @authorization(validate: [
{ operations: [UPDATE], where: { jwt: { roles: { includes: "admin" } } } }
{ operations: [UPDATE], where: { node: { locked: { eq: false } } } }
]) {
id: ID!
locked: Boolean!
}
如果您想结合“用户必须是管理员”和“locked 属性必须为 false”这两个规则来更新 User 节点,请在单个规则中使用 AND 将它们都添加到 where 字段中:
type User @node @authorization(validate: [
{ operations: [UPDATE], where: { AND: [{ jwt: { roles: { includes: "admin" } } }, { node: { locked: {eq: false} } }] } }
]) {
id: ID!
locked: Boolean!
}