如何使用自定义角色更新 Firestore 规则
How to update Firestore Rules with custom Roles
如何配置规则以根据另一个 collection(用户)中定义的自定义用户角色控制 Reads/Writes 和 collection(记录)上的删除?
---- 用户 Collection ----
USERS: {
<RandomID1> : { uid: 234, email: "abc@xyz.com", role: "ENDUSER" },
<RandomID2> : { uid: 100, email: "def@xyz.com", role: "ADMIN" }
}
----记录Collection----
RECORDS: {
<RandomID1> : { uid: "234", name: "Record 123" },
<RandomID2> : { uid: "234", name: "Record 456" },
<RandomID3> : { uid: "999", name: "Record 999" } /* another user's record */
}
---- 当前规则----
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
假设用户已登录网络应用程序并使用 client-side Firebase SDK,如何实现以下情况?
国际足联:USERS.RandomID1.role = 'ENDUSER'
- 如何限制用户只能从 RECORDS 中读取他们的记录,
但不是别人的?
如何将更新仅限于他们的
RECORDS 中的记录?
如何限制对 RECORDS 中所有记录的删除?
- 如何限制 collections(/COLLECTION**) 其余部分的所有 CRUD 操作,RECORDS 除外?
国际足联:USERS.RandomID1.role = 'ADMIN'
- 如何启用此(管理员)用户执行所有 CRUD 操作
记录?
那么,如何重写或更新规则来控制这些操作呢?如果没有,是否有更好的设计或替代方案?
注意:我们需要处理这些情况,以阻止一些 users/hackers 可能尝试打开浏览器 console/inspect window,并在有或没有的情况下执行 firestore 查询任何条件。
感谢您的帮助!
对于 5 你需要为你的管理员定义 custom claims,下面我假设一个字段 isadmin
为管理员设置为 true。
以下规则应该是一个好的开始:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// 4: Will restrict all others access
match /records/{recordid} {
// 1+5(read): restrict reads
allow read: if request.auth != null
&& (resource.data.uid == request.auth.uid || request.auth.token.isadmin);
// 2+3+5(write): +create as a bonus
allow write: if request.auth != null
&& (request.resource.data.uid == request.auth.uid || request.auth.token.isadmin);
}
}
}
这是我的最终答案:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
//Rule on a Collection Groups, instead of simple Collection
match /{NestedSubCollections=**}/<COMMON_COLLECTION-NAME>/{doc} {
allow create: if isSignedIn() && isAdmin();
allow read: if isSignedIn() && (isAdmin() || isThisUserRecord(resource.data.<CUST_USER-ID-FIELD>));
allow update: if isSignedIn() && (isAdmin() || isThisUserRecord(resource.data.<CUST_USER-ID-FIELD>));
allow delete: if isSignedIn() && isAdmin();
}
//Collection UserDB, to validate profile updates
match /UserDB/{userId=**} {
allow create: if isSignedIn() && isAdmin();
allow read: if isSignedIn() && (isAdmin() || hasUserProfile(resource.data.<CUST_USER-ID-FIELD>));
allow update: if isSignedIn() && (isAdmin() || hasUserProfile(resource.data.<CUST_USER-ID-FIELD>));
allow delete: if isSignedIn() && isAdmin();
}
//Checking if user is signed-in
function isSignedIn() {
return request.auth != null;
}
//Checking user's admin status, without the context of accessing collection, but directly
function isAdmin() {
return get(/databases/$(database)/documents/UserDB/$(request.auth.uid)).data.<CUST_ROLE-FIELD> == "<ADMIN-ROLE-NAME>";
}
//Check whether a current record belong to logged-in user; by <CUST_USER-ID-FIELD>, not oAuth-ID
function isThisUserRecord(custUserId) {
return get(/databases/$(database)/documents/UserDB/$(request.auth.uid)).data.<CUST_USER-ID-FIELD> == custUserId;
}
//Check whether a logged-in user has existing profile or not
function hasUserProfile(userOauthId) {
return userOauthId == request.auth.uid;
}
}
}
它在我的生产应用程序中运行得非常好,并且无需在应用程序中编写任何代码,一切都得到了保护!
如何测试?
- 用
和 更新了 UserDB 中的一条用户记录作为值
- 然后转到您的前端 Web 应用程序,转到浏览器控制台,尝试访问 Firestore 查询并验证记录和结果
- 如果是非管理员用户,那么他只能Read/Update按照我们上面的规则,其他查询都会失败。
- 请注意,出于安全原因,create/delete 是在后端通过云功能执行的。
总而言之,管理员可以对所有记录执行任何操作,但非管理员用户只能对自己的记录进行有限的Read/Update操作。
您可能需要根据其他用例进行一些调整。有什么事请告诉我。
如何配置规则以根据另一个 collection(用户)中定义的自定义用户角色控制 Reads/Writes 和 collection(记录)上的删除?
---- 用户 Collection ----
USERS: {
<RandomID1> : { uid: 234, email: "abc@xyz.com", role: "ENDUSER" },
<RandomID2> : { uid: 100, email: "def@xyz.com", role: "ADMIN" }
}
----记录Collection----
RECORDS: {
<RandomID1> : { uid: "234", name: "Record 123" },
<RandomID2> : { uid: "234", name: "Record 456" },
<RandomID3> : { uid: "999", name: "Record 999" } /* another user's record */
}
---- 当前规则----
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
假设用户已登录网络应用程序并使用 client-side Firebase SDK,如何实现以下情况?
国际足联:USERS.RandomID1.role = 'ENDUSER'
- 如何限制用户只能从 RECORDS 中读取他们的记录, 但不是别人的?
如何将更新仅限于他们的 RECORDS 中的记录?
如何限制对 RECORDS 中所有记录的删除?
- 如何限制 collections(/COLLECTION**) 其余部分的所有 CRUD 操作,RECORDS 除外?
国际足联:USERS.RandomID1.role = 'ADMIN'
- 如何启用此(管理员)用户执行所有 CRUD 操作 记录?
那么,如何重写或更新规则来控制这些操作呢?如果没有,是否有更好的设计或替代方案?
注意:我们需要处理这些情况,以阻止一些 users/hackers 可能尝试打开浏览器 console/inspect window,并在有或没有的情况下执行 firestore 查询任何条件。
感谢您的帮助!
对于 5 你需要为你的管理员定义 custom claims,下面我假设一个字段 isadmin
为管理员设置为 true。
以下规则应该是一个好的开始:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// 4: Will restrict all others access
match /records/{recordid} {
// 1+5(read): restrict reads
allow read: if request.auth != null
&& (resource.data.uid == request.auth.uid || request.auth.token.isadmin);
// 2+3+5(write): +create as a bonus
allow write: if request.auth != null
&& (request.resource.data.uid == request.auth.uid || request.auth.token.isadmin);
}
}
}
这是我的最终答案:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
//Rule on a Collection Groups, instead of simple Collection
match /{NestedSubCollections=**}/<COMMON_COLLECTION-NAME>/{doc} {
allow create: if isSignedIn() && isAdmin();
allow read: if isSignedIn() && (isAdmin() || isThisUserRecord(resource.data.<CUST_USER-ID-FIELD>));
allow update: if isSignedIn() && (isAdmin() || isThisUserRecord(resource.data.<CUST_USER-ID-FIELD>));
allow delete: if isSignedIn() && isAdmin();
}
//Collection UserDB, to validate profile updates
match /UserDB/{userId=**} {
allow create: if isSignedIn() && isAdmin();
allow read: if isSignedIn() && (isAdmin() || hasUserProfile(resource.data.<CUST_USER-ID-FIELD>));
allow update: if isSignedIn() && (isAdmin() || hasUserProfile(resource.data.<CUST_USER-ID-FIELD>));
allow delete: if isSignedIn() && isAdmin();
}
//Checking if user is signed-in
function isSignedIn() {
return request.auth != null;
}
//Checking user's admin status, without the context of accessing collection, but directly
function isAdmin() {
return get(/databases/$(database)/documents/UserDB/$(request.auth.uid)).data.<CUST_ROLE-FIELD> == "<ADMIN-ROLE-NAME>";
}
//Check whether a current record belong to logged-in user; by <CUST_USER-ID-FIELD>, not oAuth-ID
function isThisUserRecord(custUserId) {
return get(/databases/$(database)/documents/UserDB/$(request.auth.uid)).data.<CUST_USER-ID-FIELD> == custUserId;
}
//Check whether a logged-in user has existing profile or not
function hasUserProfile(userOauthId) {
return userOauthId == request.auth.uid;
}
}
}
它在我的生产应用程序中运行得非常好,并且无需在应用程序中编写任何代码,一切都得到了保护!
如何测试?
- 用
和 更新了 UserDB 中的一条用户记录作为值 - 然后转到您的前端 Web 应用程序,转到浏览器控制台,尝试访问 Firestore 查询并验证记录和结果
- 如果是非管理员用户,那么他只能Read/Update按照我们上面的规则,其他查询都会失败。
- 请注意,出于安全原因,create/delete 是在后端通过云功能执行的。
总而言之,管理员可以对所有记录执行任何操作,但非管理员用户只能对自己的记录进行有限的Read/Update操作。
您可能需要根据其他用例进行一些调整。有什么事请告诉我。