如何在 Firebase FireStore 中实现此安全逻辑?
How do I achieve this security logic in Firebase FireStore?
下图显示了我需要为我的 firebase firestore 申请的安全规则的逻辑。
描述
我的应用程序允许用户身份验证,我手动激活客户帐户。激活后,他们可以将用户添加到他们的数据库集合中,以及对他们的数据库执行操作。我在下面用 'Organization' 说明了每个客户端,每个客户端都有多个用户,它们应该只能访问数据库的特定部分 collections/documents。
每个组织都有一个管理员用户,该用户对该特定组织的数据库集合具有完全访问权限。每个用户(来自每个组织)都可以访问节点 'Elements',以及他们自己的 UID 生成的文档和集合。
看来我需要自定义声明授权才能实现这一点。我想知道是否存在一些替代方案,比如在我的 fireStore 中添加一些特定的安全规则以使其工作,或者除了 firebase admin sdk 工具之外的任何其他替代方案,因为它很耗时而且我不是专业的后端开发人员。
其他详情
我用颤振。我的应用程序允许客户验证和创建他们的数据库集合。客户端添加具有不同角色的用户(作为团队成员)(这会影响 collection/document 他们可以访问的内容)
这个安全规则逻辑是我现在坚持的主要内容。
我非常感谢可以帮助我实现目标的建议和示例。
插图
我现在的 FireStore 安全规则
一个可能的解决方案:
每个组织都应该包含一个字符串列表(userIds),只有在这个列表中有userId的用户才能访问组织集合和文档。
数据库结构:
organisation_1:
userIds (field containing list of user ids - []<String>):
adminId (field containing admin id - String):
admin (collection):
users (collection):
elements (collection):
premium (collection):
organisation_2:
安全规则
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isLoggedIn() {
// only true if user is logged in
return request.auth != null;
}
match /organisation/{organisationId} {
function prefix() {
return /databases/$(database)/documents/organisation/$(organisationId);
}
function isAdmin() {
// only true if admin
return isLoggedIn() && request.auth.uid == get(/$(prefix())).data.adminId;
}
function isUser() {
// only true if user
return isLoggedIn() && request.auth.uid in get(/$(prefix())).data.usersId;
}
function isDataOwner(dataId) {
// only true if user is admin or userId is the document id.
// this rule should allow each user access to their own UID-
// generated docs and collections only
return isLoggedIn() && (isAdmin() || dataId == request.auth.uid);
}
// since userIds list is organisation data, we should prevent any
// user from editing it (or only allow admin to edit it).
// if you are using cloud function to update userIds list, set this
// to false. Cloud function does not need access.
allow write: if isAdmin();
allow read: if true;
match /Elements/{elementsId=**} {
// allow access to the entire Elements collection and
// subcollections if isAdmin or isUser.
allow read, write: if isAdmin() || isUser();
}
match /settings/{userId} {
// allow access only if document id is your userId
allow read, write: if isDataOwner(userId);
}
match /adminDocs/{docId} {
// only allow admin
allow read, write: if isAdmin();
}
}
}
}
然后您可以使用云函数来使您的 userIds 列表保持最新。示例:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const db = admin.firestore();
exports.onCreate = functions.firestore
.document("/organisation/{organisationId}/users/{userId}")
.onCreate((_, context) => {
const params = context.params;
const organisationId = params.organisationId;
const userId = params.userId;
const data = {
userIds: admin.firestore.FieldValue.arrayUnion(userId),
};
return db.doc(`/organisation/${organisationId}`)
.set(data, { merge: true });
});
exports.onDelete = functions.firestore
.document("/organisation/{organisationId}/users/{userId}")
onDelete((_, context) => {
const params = context.params;
const organisationId = params.organisationId;
const userId = params.userId;
const data = {
userIds: admin.firestore.FieldValue.arrayRemove(userId),
};
return db.doc(`/organisation/${organisationId}`)
.set(data, { merge: true });
});
您可以通过在管理员创建新用户时将 userid 添加到 userId 列表来避免此云功能。但是云函数更干净(使用它)。
更新
$(database)
是您的 firestore 数据库的名称。
{database}
(我的安全规则中的第 3 行)告诉规则将数据库的实际名称保存到 database
变量中。
prefix()
returns 组织文档的路径。
如果用户尝试访问此路径中的文档 organisation/12345/users/67890
,则 $(database)
是 default
并且 prefix()
returns /databases/default/documents/organisation/12345/
您可以前往 firestore docs 了解如何使用 $(database)
和路径 (prefix()
)。
下图显示了我需要为我的 firebase firestore 申请的安全规则的逻辑。
描述 我的应用程序允许用户身份验证,我手动激活客户帐户。激活后,他们可以将用户添加到他们的数据库集合中,以及对他们的数据库执行操作。我在下面用 'Organization' 说明了每个客户端,每个客户端都有多个用户,它们应该只能访问数据库的特定部分 collections/documents。 每个组织都有一个管理员用户,该用户对该特定组织的数据库集合具有完全访问权限。每个用户(来自每个组织)都可以访问节点 'Elements',以及他们自己的 UID 生成的文档和集合。
看来我需要自定义声明授权才能实现这一点。我想知道是否存在一些替代方案,比如在我的 fireStore 中添加一些特定的安全规则以使其工作,或者除了 firebase admin sdk 工具之外的任何其他替代方案,因为它很耗时而且我不是专业的后端开发人员。
其他详情 我用颤振。我的应用程序允许客户验证和创建他们的数据库集合。客户端添加具有不同角色的用户(作为团队成员)(这会影响 collection/document 他们可以访问的内容) 这个安全规则逻辑是我现在坚持的主要内容。
我非常感谢可以帮助我实现目标的建议和示例。
插图
我现在的 FireStore 安全规则
一个可能的解决方案: 每个组织都应该包含一个字符串列表(userIds),只有在这个列表中有userId的用户才能访问组织集合和文档。
数据库结构:
organisation_1:
userIds (field containing list of user ids - []<String>):
adminId (field containing admin id - String):
admin (collection):
users (collection):
elements (collection):
premium (collection):
organisation_2:
安全规则
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function isLoggedIn() {
// only true if user is logged in
return request.auth != null;
}
match /organisation/{organisationId} {
function prefix() {
return /databases/$(database)/documents/organisation/$(organisationId);
}
function isAdmin() {
// only true if admin
return isLoggedIn() && request.auth.uid == get(/$(prefix())).data.adminId;
}
function isUser() {
// only true if user
return isLoggedIn() && request.auth.uid in get(/$(prefix())).data.usersId;
}
function isDataOwner(dataId) {
// only true if user is admin or userId is the document id.
// this rule should allow each user access to their own UID-
// generated docs and collections only
return isLoggedIn() && (isAdmin() || dataId == request.auth.uid);
}
// since userIds list is organisation data, we should prevent any
// user from editing it (or only allow admin to edit it).
// if you are using cloud function to update userIds list, set this
// to false. Cloud function does not need access.
allow write: if isAdmin();
allow read: if true;
match /Elements/{elementsId=**} {
// allow access to the entire Elements collection and
// subcollections if isAdmin or isUser.
allow read, write: if isAdmin() || isUser();
}
match /settings/{userId} {
// allow access only if document id is your userId
allow read, write: if isDataOwner(userId);
}
match /adminDocs/{docId} {
// only allow admin
allow read, write: if isAdmin();
}
}
}
}
然后您可以使用云函数来使您的 userIds 列表保持最新。示例:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const db = admin.firestore();
exports.onCreate = functions.firestore
.document("/organisation/{organisationId}/users/{userId}")
.onCreate((_, context) => {
const params = context.params;
const organisationId = params.organisationId;
const userId = params.userId;
const data = {
userIds: admin.firestore.FieldValue.arrayUnion(userId),
};
return db.doc(`/organisation/${organisationId}`)
.set(data, { merge: true });
});
exports.onDelete = functions.firestore
.document("/organisation/{organisationId}/users/{userId}")
onDelete((_, context) => {
const params = context.params;
const organisationId = params.organisationId;
const userId = params.userId;
const data = {
userIds: admin.firestore.FieldValue.arrayRemove(userId),
};
return db.doc(`/organisation/${organisationId}`)
.set(data, { merge: true });
});
您可以通过在管理员创建新用户时将 userid 添加到 userId 列表来避免此云功能。但是云函数更干净(使用它)。
更新
$(database)
是您的 firestore 数据库的名称。
{database}
(我的安全规则中的第 3 行)告诉规则将数据库的实际名称保存到 database
变量中。
prefix()
returns 组织文档的路径。
如果用户尝试访问此路径中的文档 organisation/12345/users/67890
,则 $(database)
是 default
并且 prefix()
returns /databases/default/documents/organisation/12345/
您可以前往 firestore docs 了解如何使用 $(database)
和路径 (prefix()
)。