我一直在一遍又一遍地尝试重组我的规则,以便能够访问这些文档,但没有运气。
我有一个“网络”集合和一个“成员”子集合。在网络文档中有两个字段,loginRequired 和membershipRequired,它们确定访问网络文档及其子集合需要什么级别的身份验证。
我已在下面附上我的规则,并且已确认membershipRequired / loginRequired 字段均位于网络文档的顶层。
我在各个级别都遭到拒绝。我可能做错了什么?
match /networks/{networkID} {
allow read: if (isAdmin()
|| !(planRequiresAuth())
|| (isLoggedIn()
&& (resource.data.membershipRequired
? (isPlanMember(database, networkID)
|| isProviderPlanMember(database, networkID))
: true)
)
)
match /{document=**} {
allow read: if (isAdmin()
|| !(get(/databases/$(database)/documents/networks/$(networkID))
.data.loginRequired)
|| (isLoggedIn()
&& (get(/databases/$(database)/documents/networks/$(networkID))
.data.membershipRequired
? (isPlanMember(database, networkID)
|| isProviderPlanMember(database, networkID))
: true)
)
)
}
}
// Utility Functions
function isAdmin() {
return hasRole('ADMIN')
}
function planRequiresAuth() {
return (resource.data.loginRequired || resource.data.membershipRequired)
}
function isLoggedIn() {
return request.auth != null
}
function isPlanMember(database, networkID) {
// Check if the document ID is in the users memberships
let userId = request.auth.uid;
return exists(/databases/$(database)/documents/networks/$(networkID)/members/$(userId))
}
function isProviderPlanMember(database, networkID) {
// Check if the document ID is in the users memberships
let orgId = request.auth.token.meta.organizationId;
return ((resource.data.membershipRequired == true) ? (exists(/databases/$(database)/documents/networks/$(networkID)/members/$(orgId))) : true)
}
function hasRole(role) {
return role in request.auth.token.roles
}
我尝试将其设置为允许所有读取,效果很好。 我尝试过允许所有子集合读取并且它也有效,但我有一种感觉这不是我想要的,因为子集合也需要门控。
编辑 返回权限被拒绝的查询。由于第一个查询被拒绝,第二个查询尚未被调用。我将两者都包含在内以获取完整的上下文。
collection('networks')
.where('slug', '==', networkSlug)
.get()
.catch(err => {
console.warn(' ** Error fetching network by slug') // eslint-disable-line no-console
console.log(err) // eslint-disable-line no-console
if (err?.code === 'permission-denied') {
return { error: err, code: 'permission-denied' }
}
return { error: err, code: 'error-fetching' }
})
collection('networks')
.doc(networkId)
.collection('landerInfo')
.get()
.catch(err => {
console.log(err) // eslint-disable-line no-console
return { error: err, code: 'error-fetching' }
})
要对此进行调试,您应该转到 Firestore 控制台,然后在“规则游乐场”中运行查询,而不是在应用程序中运行查询。它将更准确地强调其被拒绝的逻辑。
无论如何,这里的问题是下面一行:
exists(/databases/$(database)/documents/networks/$(networkID)/members/$(userId))
Firestore 接受或拒绝查询的决定是在执行查询之前做出的(文档将其描述为“规则不是过滤器”)。在判断接受查询时,
networkId
还不知道(因为查询约束中没有指定,还没有得到查询结果),无法运行exists
查询上面不知道networkId
。