基于Firestore的角色权限系统:未知用户共享故事的规则与查询问题
解决Firestore中分享故事给未注册用户的权限与查询问题
我来帮你搞定这个场景下的Firestore规则设计和查询实现!先从数据结构入手,这是所有权限逻辑的基础。
1. 数据结构设计
首先需要调整你的Firestore集合结构,支持未注册用户的邮箱分享:
故事集合 (stories)
每个故事文档包含以下核心字段:
creatorUid: 字符串,故事创建者的Firebase Auth UIDsharedWithEmails: 数组,存储被分享的用户邮箱(用户B未注册时先存邮箱,注册后匹配) title: 字符串,故事标题content: 字符串,故事内容
用户集合 (users)
每个用户文档用Firebase Auth的UID作为文档ID,包含:
email: 字符串,用户注册时的邮箱(用于和stories.sharedWithEmails关联)
2. Firestore安全规则实现
下面的规则会严格限制故事的访问权限:只有创建者,或者邮箱在sharedWithEmails数组里的注册用户才能读取故事。
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // 故事集合规则 match /stories/{storyId} { // 创建规则:只有登录用户能创建,且creatorUid必须是当前用户UID allow create: if request.auth != null && request.resource.data.creatorUid == request.auth.uid; // 更新/删除规则:只有故事创建者能操作 allow update, delete: if request.auth != null && resource.data.creatorUid == request.auth.uid; // 读取规则:两种情况允许访问 allow read: if request.auth != null && ( // 情况1:当前用户是故事创建者 resource.data.creatorUid == request.auth.uid || // 情况2:当前用户的邮箱在sharedWithEmails数组中 request.auth.token.email in resource.data.sharedWithEmails ); } // 用户集合规则:用户只能访问自己的文档 match /users/{userId} { allow read, write: if request.auth != null && request.auth.uid == userId; } } }
3. 查询实现(前端/后端)
Firestore的规则是查询过滤,也就是说你的查询必须和规则条件匹配,否则会被拒绝。以下是不同场景的查询示例:
场景1:用户A(创建者)查询自己的故事
// 前端JavaScript示例 import { getFirestore, collection, query, where } from "firebase/firestore"; const db = getFirestore(); const currentUserUid = auth.currentUser.uid; // 查询自己创建的所有故事 const q = query( collection(db, "stories"), where("creatorUid", "==", currentUserUid) );
场景2:用户B(注册后)查询自己能访问的故事
用户B注册后,我们可以通过其邮箱查询所有分享给自己的故事,同时包含自己创建的故事:
const currentUserEmail = auth.currentUser.email; const currentUserUid = auth.currentUser.uid; // 查询条件:要么是自己创建的,要么邮箱在sharedWithEmails里 const q = query( collection(db, "stories"), where("creatorUid", "==", currentUserUid), or(where("sharedWithEmails", "array-contains", currentUserEmail)) );
场景3:用户B通过邮件链接访问特定故事
当用户B点击邮件里的故事链接(包含storyId),注册后可以直接查询该故事:
const storyId = "从邮件链接中获取的故事ID"; const docRef = doc(db, "stories", storyId); // 直接获取文档,Firestore规则会自动验证权限 getDoc(docRef).then((doc) => { if (doc.exists()) { // 渲染故事内容 } else { // 无权限或文档不存在 } });
4. 分享流程的补充说明
- 用户A发送邮件时,需要将故事的
storyId嵌入到邮件的链接中(比如https://yourapp.com/story?storyId=xxx) - 用户B注册后,应用可以从链接中提取
storyId,然后尝试获取该文档——此时Firestore规则会检查用户B的邮箱是否在sharedWithEmails数组中,允许则返回内容。
内容的提问来源于stack exchange,提问作者ralphinator80
相关产品推荐
相关产品推荐

