我正在使用具有以下数据库的应用程序:
organizations/{ordId}
organizationsPrivateData/{orgId}
events/{eventId}
组织由以下组成:
事件:
organizationalprivatedata :
我有两种情况要处理:
组织是“公共的”(true),因此所有事件都是可读的,没有任何标记。这是通过以下安全规则isOrganizationPublic
完成的:
// DB Read
function organizationData(organizationId) { return get(/databases/$(database)/documents/organizations/$(organizationId)).data }
function organizationPrivateData(organizationId) { return get(/databases/$(database)/documents/organizationsPrivateData/$(organizationId)).data }
// Auth management
function authenticated() { return request.auth.uid != null }
function isAdmin(data) { return data.owner == request.auth.uid || request.auth.uid in data.members}
function isEmailVerified() { return request.auth.token.email_verified == true }
// Tokens management
function isOrganizationReadAccepted (organizationId, readToken) {
let organization = organizationData(organizationId);
return isOrganizationPublic(organization);
}
function isOrganizationPublic (organization) { return organization.public == true }
function isReadTokenValid (organizationId, token) { return organizationPrivateData(organizationId).readToken == token }
match /events/{eventId} {
allow read: if isOrganizationReadAccepted(resource.data.organizationId, debug(resource.data.token));
}
match /organizations/{organizationId} {
allow get: if isOrganizationReadAccepted(organizationId, request.resource.data.token);
}
match /organizationsPrivateData/{orgId} {
allow read: if authenticated() && isAdmin(organizationData(resource.data.organizationId));
}
organization.public = false
。然后isOrganizationPublic
返回false,我们可以执行三元操作来进行其他检查。那里的目标是检查organizationPrivateData
以确保readToken
有效。我的想法是像这样通过where子句从客户端传递令牌:
app
.collection('events')
.where('organizationId', "==", "org1")
.where('token', 'array-contains-any', ["",'azerty'])
.get()
规则:return isOrganizationPublic(organization) ? true : isReadTokenValid(organizationId, resource.data.token[0])
问题:我在这里被屏蔽。如果可行,我需要在每个事件上都有一个“令牌”字段,并带有一个空字符串,这对我而言是可以的。因此,如果通过了安全性,则真正的“ where”可以返回所有授予的事件。
在对可用的where运算符(在array-contains,array-contains-any)中进行其他检查时,似乎:
in
:规则中的值是一个字符串,每个数组值可能多次调用array-contains
:是一个不同的结构,看起来像constraint_value { simple_constraints { comparator: LIST_CONTAINS value { string_value: "" } } }
。也只能得到一个值array-contains-any
:看起来像array-contains
,但内部包含所有where数组。可能的解决方案不是最优的:在每个“事件”中都包含令牌。这会奏效,但更新令牌更新,我需要更改该组织的所有活动,这不是最佳选择,而且可能还需要一些时间。
不是解决方案:
hasAny
和'in'运算符,in不具有所有数组值。array-contains-any
不是数组。github here上有完整的源文件
可能的相关问题:Firestore Security Rules for Query with Array Contains
答案 0 :(得分:1)
您想要以Firestore中不可能的方式在两个集合之间进行联接。正如您自己提到的那样,唯一的解决方案是在每个token
文档中添加event
。
您可以使用此解决方案,这样就不必在令牌更新时更新所有event
文档:
organizationsPrivateData
:使用包含所有历史令牌的数组readTokens
,将新令牌附加到续签上
将您的规则更改为:
function isReadTokenValid (organizationId, token) {
return token in organizationPrivateData(organizationId).readTokens;
}