【发布时间】:2020-11-07 17:41:39
【问题描述】:
我正在使用以下数据库开发应用程序:
organizations/{ordId}
organizationsPrivateData/{orgId}
events/{eventId}
一个组织由以下人员组成:
- 所有者:uid
- 公共:布尔值
一个事件:
- 标题:字符串
- organizationId:字符串
一个organizationPrivateData:
- organizationId:字符串(虽然 organizationPrivateData id 本身就是 organizationId)
- readToken: 字符串
我要处理两个案例:
案例一
该组织是“公共的”(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));
}
案例 2
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 运算符(in、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
【问题讨论】:
标签: javascript firebase google-cloud-firestore firebase-security