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

如何在Firebase Firestore中构建多租户SaaS应用权限体系

实现Firebase Firestore多租户自定义角色与权限机制

针对你的多租户场景,我之前做过类似的落地方案,核心思路是租户数据隔离+自定义角色权限映射+Firebase安全规则动态校验,下面分几个关键部分拆解:

一、数据结构设计(核心基础)

首先要把租户、用户、角色、业务数据做清晰的层级隔离,推荐这种高扩展性的结构:

tenants/
  {tenantId}/          // 每个租户对应一个文档,比如tenantId设为customerA、customerB
    name: "客户A",
    roles: {           // 租户自定义的角色-权限映射,由租户Admin自主维护
      "Admins": {
        canManageRoles: true,
        canEditAllData: true,
        canInviteUsers: true
      },
      "Managers": {
        canEditTeamData: true,
        canViewReports: true
      },
      "Associates": {
        canViewOwnData: true
      },
      "Contractors": { // 租户可随时新增自定义角色
        canViewPublicData: true,
        canSubmitRequests: true
      }
    },
    users/             // 该租户专属的用户子集合
      {userId}/        // 关联Firebase Auth的用户ID
        displayName: "customerAUser1",
        role: "Admins",
        email: "user1@customerA.com"
business_data/
  {tenantId}/          // 业务数据严格按租户隔离,比如订单、客户信息等
    orders/
      {orderId}/
    customers/
      {customerId}/

这种设计的优势:

  • 天然实现租户数据物理隔离,从根源避免跨租户访问风险
  • 租户Admin无需依赖开发者,直接在roles字段里新增/修改角色权限
  • 用户与租户的关联关系明确,权限校验逻辑更直观

二、用户身份与角色绑定

用户登录后,需要将其与所属租户、角色关联,有两种常用方案:

1. Firebase Auth自定义Claims(适合角色不频繁变更的场景)

租户Admin通过Firebase Admin SDK给用户设置自定义Claims,携带tenantId和role信息:

// Admin SDK 代码示例(Node.js)
const admin = require('firebase-admin');

async function assignUserRole(userId, tenantId, role) {
  await admin.auth().setCustomUserClaims(userId, {
    tenantId: tenantId,
    role: role
  });
}

安全规则里可以直接读取request.auth.token.tenantId和request.auth.token.role,校验速度快,性能开销低。

2. 结合Firestore用户文档(适合角色频繁变更的场景)

如果租户经常调整用户角色,自定义Claims的更新需要调用Admin SDK且有延迟,这时可以在安全规则中直接读取租户下的用户文档:

function getCurrentUserRole() {
  return get(/databases/$(database)/documents/tenants/$(request.auth.token.tenantId)/users/$(request.auth.uid)).data.role;
}

注意:这种方式会增加Firestore的读取次数,需要在灵活性和性能之间做权衡。

三、Firebase安全规则实现

核心逻辑是:先验证用户属于当前租户,再根据其角色的权限配置校验操作权限。

下面是完整的规则示例:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // 通用函数:获取当前租户的角色权限配置
    function getTenantRoleConfig() {
      return get(/databases/$(database)/documents/tenants/$(request.auth.token.tenantId)).data.roles;
    }

    // 通用函数:获取当前用户的权限集合
    function getCurrentUserPermissions() {
      // 用自定义Claims的情况
      let userRole = request.auth.token.role;
      // 如果用Firestore用户文档,替换成:
      // let userRole = get(/databases/$(database)/documents/tenants/$(request.auth.token.tenantId)/users/$(request.auth.uid)).data.role;
      return getTenantRoleConfig()[userRole];
    }

    // 租户文档权限:仅该租户的Admin可修改角色配置
    match /tenants/{tenantId} {
      allow read: if request.auth.token.tenantId == tenantId;
      allow update: if request.auth.token.tenantId == tenantId && getCurrentUserPermissions().canManageRoles == true;
    }

    // 租户用户管理:Admin可增删改用户,其他角色仅可查看
    match /tenants/{tenantId}/users/{userId} {
      allow read: if request.auth.token.tenantId == tenantId;
      allow create, update, delete: if request.auth.token.tenantId == tenantId && getCurrentUserPermissions().canManageRoles == true;
    }

    // 业务数据权限:根据角色权限动态校验
    match /business_data/{tenantId}/{collection}/{docId} {
      allow read: if request.auth.token.tenantId == tenantId && 
        (getCurrentUserPermissions().canEditAllData == true || 
         getCurrentUserPermissions().canViewReports == true ||
         getCurrentUserPermissions().canViewOwnData == true ||
         getCurrentUserPermissions().canViewPublicData == true);
      allow write: if request.auth.token.tenantId == tenantId &&
        (getCurrentUserPermissions().canEditAllData == true ||
         getCurrentUserPermissions().canEditTeamData == true ||
         getCurrentUserPermissions().canSubmitRequests == true);
    }
  }
}

四、租户Admin自定义角色的流程

  1. 租户Admin登录后,访问自己租户的tenants/{tenantId}文档
  2. 在roles字段中新增/修改角色,比如添加Auditors角色并配置权限:
    "Auditors": {
      "canViewAllReports": true,
      "canExportData": true
    }
    
  3. 给租户下的目标用户分配该角色(通过后台界面调用assignUserRole函数)
  4. 安全规则会自动读取新的角色权限,无需修改规则代码

五、优化与注意事项

  • 权限粒度细化:可以把权限拆到单个业务集合,比如canEditOrders、canViewCustomers,让租户Admin能精准控制
  • 性能优化:优先使用自定义Claims缓存租户和角色信息,减少安全规则中的Firestore读取;如果角色变更频繁,可以定期同步Claims或结合实时数据库做缓存
  • 跨租户防护:所有业务数据必须按tenantId隔离,安全规则中始终校验request.auth.token.tenantId == tenantId,彻底避免数据泄露

内容的提问来源于stack exchange,提问作者Raja Rao

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:13:24