KeystoneJS"filter"与"Item"列表访问控制



我正试图更深入地理解过滤器和项目访问控制之间的区别。

基本上,我理解Item访问控制是一种更高阶的检查,并且将在GraphQL过滤器之前运行。我的问题是,如果我在更新时对特定字段进行筛选,例如groupID或类似的内容,我是否需要在项目访问控制中进行同样的检查?这将导致额外的数据库查询,该查询将成为筛选器的一部分。

对此有什么想法吗?

TL;DR回答。。。

如果我正在对特定字段进行筛选[..],我是否需要在项目访问控制中进行相同的检查?

不,您只需要在一个地方或另一个地方应用限制。

一般来说,如果您可以使用filter访问控制(即作为graphQL样式的过滤器,提供args(来描述限制,那么这是最好的方法。但是,如果您的访问控制需要根据当前项中的值或正在进行的特定更改而表现不同,则可能需要item的访问控制。

背景

Keystone中的访问控制可能有点让人难以理解,但它实际上非常强大,设计背后有充分的理由。让我来澄清一下:

过滤器访问控制是通过向针对数据库运行的查询添加条件来应用的

想象一下,一个包含用户和帖子列表的内容系统。用户可以撰写帖子,但有些帖子也可以由每个人编辑。Post列表配置可能有如下内容:

// .. 
access: {
filter: {
update: () => ({ isEditable: { equals: true } }),
}
},
// ..

这实际上是在为该列表运行的所有更新查询中添加一个条件。所以,如果你更新这样的帖子:

mutation {
updatePost(where: { id: "123"}, data: { title: "Best Pizza" }) {
id name
}
}

运行的SQL可能如下所示:

update "Post"
set title = 'Best Pizza'
where id = 234 and "isEditable" = true;

请注意更新过滤器自动添加的isEditable条件。这在某些方面非常强大,但也有其局限性——过滤器访问控制函数只能返回GraphQL风格的过滤器,这阻止了它们在无法过滤的虚拟字段(因为它们不存在于数据库中(上操作。它们也不能根据项目的当前值或正在执行的特定更新应用不同的过滤器。

过滤器访问控制功能可以访问当前会话,因此可以执行以下操作:

filter: {
// If the current user is an admin don't apply the usual filter for editability
update: (session) => {
return session.isAdmin ? {} : { isEditable: { equals: true } };
},
}

但你不能这样做,引用当前的项目数据:

filter: {
// ⚠️ this is broken; filter access control functions don't receive the current item ⚠️
// The current user can update any post they authored, regardless of the isEditable flag
update: (session, item) => {
return item.author === session.itemId ? {} : { isEditable: { equals: true } };
},
}

过滤器访问控制的好处是,它不会强制Keystone在操作发生之前读取项目;过滤器被有效地添加到操作本身。这可以使它们对DB更高效,但确实在一定程度上限制了它们。请注意,钩子之类的东西也可能导致在执行操作之前读取项目,因此这种性能差异并不总是明显的。

项目访问控制在应用层中应用,方法是根据现有项目和/或提供的新数据评估提供的JS函数

这使得他们在某些方面更加强大。例如,您可以实现前面的用例,允许作者更新自己的帖子,如下所示:

item: {
// The current user can update any post they authored, regardless of the isEditable flag
update: (session, item) => {
return item.author === session.itemId || item.isEditable;
},
}

或者,通过引用inputData参数,根据正在进行的特定更新添加进一步的限制。

因此,项目访问控制可以说更强大,但它们可能会对性能产生重大影响——与其说是对可能少量执行的突变,不如说是对读取操作。事实上,Keystone不允许您为read操作定义项目访问控制。如果你停下来思考一下,你可能会明白为什么——这样做需要从数据库中读取列表中的所有项目,并在每次读取列表时对每个项目运行访问控制功能。因此,只能使用过滤器访问控制来限制可访问的项目。

提示:如果您认为读取需要项访问控制,请考虑将相关业务逻辑放在resolveInput挂钩中,该挂钩将相关值平坦存储为字段,然后使用筛选器访问控制引用这些字段。

希望能帮助

最新更新