管理和部署 Firebase 安全规则

使用 Firebase CLI

使用 Firebase CLI 修改和部署规则。使用 CLI,您可以借助应用代码将规则保持在版本控制之下,并将规则部署为现有部署过程的一部分。

生成配置文件

使用 Firebase CLI 配置 Firebase 项目时,您可在项目目录中创建 .rules 配置文件。使用以下命令开始配置 Firebase 项目:

Cloud Firestore

// Set up Firestore in your project directory, creates a .rules file
firebase init firestore

实时数据库

// Set up Realtime Database in your project directory, creates a .rules file
firebase init database

Storage

// Set up Storage in your project directory, creates a .rules file
firebase init storage

修改和更新您的规则

直接在 .rules 配置文件中修改规则。确保您在 Firebase CLI 中进行的所有修改都反映在 Firebase 控制台中,或者您始终使用 Firebase 控制台或 Firebase CLI 进行更新。否则,您可能会覆盖在 Firebase 控制台中所做的所有更新。

测试您的更新

使用 Firebase 模拟器在本地测试您的更新,并确认您的应用规则显示您想要的行为。

部署您的更新

您更新并测试了规则之后,就可以将它们部署到生产环境中。 使用以下命令,可以选择单独部署规则,或者将其作为正常部署过程的一部分进行部署。

Cloud Firestore

// Deploy your .rules file
firebase deploy --only firestore:rules

实时数据库

// Deploy your .rules file
firebase deploy --only database

Storage

// Deploy your .rules file
firebase deploy --only storage

使用 Firebase 控制台

您还可以从 Firebase 控制台修改和部署规则。

修改和更新您的规则

  1. 打开 Firebase 控制台,然后选择您的项目。
  2. 接着,从产品导航中选择数据库Storage
    • 数据库:选择一个数据库,然后点击规则以导航到规则编辑器。
    • Storage:点击规则以导航到规则编辑器。
  3. 直接在编辑器中修改规则。

测试您的更新

您可以使用规则模拟器直接在 Firebase 控制台中测试规则行为。在规则编辑器中打开模拟器屏幕,修改设置并点击运行。在编辑器顶部查找确认消息。

部署您的更新

如果您的更新如您所愿,对此您感到很满意,请点击发布

使用 Admin SDK

您可以使用 Node.js 版 Admin SDK 以编程方式创建、管理和部署安全规则。通过以编程方式访问,您可以执行以下操作:

  • 实现自定义工具、脚本、信息中心和 CI/CD 流水线以管理规则。
  • 更轻松地管理多个 Firebase 项目的规则。

以编程方式更新规则时,请务必避免意外更改应用的访问权限控制。在编写 Admin SDK 代码时,请特别注意安全问题,尤其是在更新或部署规则时。

另一个需要注意的重要事项是,Firebase 安全规则需要几分钟的时间才能完成部署。使用 Admin SDK 部署规则时,请务必避免出现争用的情况,即应用立即依赖于部署尚未完成的规则。如果您的用例需要频繁更新访问权限控制规则,请考虑使用 Cloud Firestore 解决方案,该方案可有效避免频繁更新时出现争用的情况。

另请注意以下限制:

  • 规则在序列化后必须小于 64KiB 的 UTF-8 编码文本。
  • 一个项目最多只能有 2500 个已部署的规则集。达到上限后,您必须先删除一些旧规则集,然后才能创建新规则集。

创建和部署 Storage 或 Cloud Firestore 规则集

使用 Admin SDK 管理安全规则的典型工作流程包括三个独立的步骤:

  1. 创建规则文件(可选)
  2. 创建规则集
  3. 发布或部署新规则集

SDK 提供了一种方法,可将这几个步骤合并到针对 Storage 和 Cloud Firestore 安全规则的单个 API 调用中。例如:

    const source = `service cloud.firestore {
      match /databases/{database}/documents {
        match /carts/{cartID} {
          allow create: if request.auth != null && request.auth.uid == request.resource.data.ownerUID;
          allow read, update, delete: if request.auth != null && request.auth.uid == resource.data.ownerUID;
        }
      }
    }`;
    // Alternatively, load rules from a file
    // const fs = require('fs');
    // const source = fs.readFileSync('path/to/firestore.rules', 'utf8');

    await admin.securityRules().releaseFirestoreRulesetFromSource(source);

此模式同样适用于具有 releaseFirestoreRulesetFromSource() 的 Storage 规则。

或者,您可以将规则文件创建为内存对象,创建规则集,并单独部署此规则集以进一步控制这些事件。 例如:

    const rf = admin.securityRules().createRulesFileFromSource('firestore.rules', source);
    const rs = await admin.securityRules().createRuleset(rf);
    await admin.securityRules().releaseFirestoreRuleset(rs);

更新实时数据库规则集

如需使用 Admin SDK 更新实时数据库规则集,请使用 admin.databasegetRules()setRules() 方法。您可以以 JSON 格式检索规则集,或者以包含注释的字符串形式检索规则集。

如需更新规则集,请使用以下语句:

    const source = `{
      "rules": {
        "scores": {
          ".indexOn": "score"
            "$uid": {
            ".read": "$uid == auth.uid",
            ".write": "$uid == auth.uid"
          }
        }
      }
    }`;
    await admin.database().setRules(source);

管理规则集

为便于管理大型规则集,Admin SDK 允许您使用 admin.securityRules().listRulesetMetadata 列出所有现有规则。例如:

    const allRulesets = [];
    let pageToken = null;
    while (true) {
      const result = await admin.securityRules().listRulesetMetadata(pageToken: pageToken);
      allRulesets.push(...result.rulesets);
      pageToken = result.nextPageToken;
      if (!pageToken) {
        break;
      }
    }

对于随着时间推移达到 2500 条规则上限的超大型规则集,您可以创建逻辑来删除固定时间周期内最旧的规则。例如,如需删除部署时间超过 30 天的所有规则集,请使用以下语句:

    const thirtyDays = new Date(Date.now() - THIRTY_DAYS_IN_MILLIS);
    const promises = [];
    allRulesets.forEach((rs) => {
      if (new Date(rs.crateTime) < thirtyDays) {
        promises.push(admin.securityRules().deleteRuleset(rs.name));
      }
    });
    await Promise.all(promises);
    console.log(`Deleted ${promises.length} rulesets.`);