You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Firestore的角色权限系统:未知用户共享故事的规则与查询问题

解决Firestore中分享故事给未注册用户的权限与查询问题

我来帮你搞定这个场景下的Firestore规则设计和查询实现!先从数据结构入手,这是所有权限逻辑的基础。

1. 数据结构设计

首先需要调整你的Firestore集合结构,支持未注册用户的邮箱分享:

故事集合 (stories)

每个故事文档包含以下核心字段:

  • creatorUid: 字符串,故事创建者的Firebase Auth UID
  • sharedWithEmails: 数组,存储被分享的用户邮箱(用户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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:15:13