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

Angular+Firestore中Map类型角色的可访问文档查询问题

问题:如何查询Firestore中当前用户可访问的寺庙文档?

背景信息

集合数据结构

Firestore的temples集合中文档结构如下:

{
 name: 'Sri Chamundeshwari temple',
 address: 'Chamundi hills, Mysore',
 roles: {
  'owner@gmail.com': 'owner',
  'admin@gmail.com': 'admin',
  'member@gmail.com': 'member',
  'viewer@gmail.com': 'viewer'
 }
}

安全规则

已设置如下安全规则,仅允许roles对象中存在的用户访问对应文档:

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    
    match /temples/{temple} {
    
      function isSignedIn() {
        return request.auth != null;
      }
    
      function getRole(rsc) {
        return rsc.data.roles[request.auth.token.email];
      }

      function isOneOfRoles(rsc, array) {
        return isSignedIn() && getRole(rsc) in array;
      }

      allow read: if isOneOfRoles(resource, ['owner', 'admin', 'member', 'viewer']);
    }
  }
}

问题描述

需要编写查询语句,获取当前登录用户可访问的所有寺庙文档(例如用户在3个文档中拥有viewer角色,预期返回这3个文档),但尝试的查询均返回权限错误:

ERROR FirebaseError: Missing or insufficient permissions.

尝试过的查询

// 尝试1:集合组查询
const q = query(
     collectionGroup(this.fireStore, "temples"), 
     where(`roles.${this.auth.currentUser?.email}`, 'array-contains', ['owner', 'administrator', 'member', 'viewer'])
);
// 尝试2:普通集合查询
const q = query(
        collection(this.fireStore, "temples"),
        where(`roles.${this.auth.currentUser?.email}`, 'array-contains', ['owner', 'administrator', 'member', 'viewer'])
);

更新:将array-contains替换为in操作符后,仍出现权限错误。


解决方案

1. 修正查询语句

你的数据结构中,roles是对象而非数组,每个用户邮箱对应一个字符串类型的角色值,因此需要使用in操作符直接匹配角色值,同时确保查询条件与安全规则的逻辑严格一致:

const userEmail = this.auth.currentUser?.email;
if (!userEmail) {
  // 处理用户未登录的边界情况
  return;
}

const q = query(
  collection(this.fireStore, "temples"),
  where(`roles.${userEmail}`, 'in', ['owner', 'admin', 'member', 'viewer'])
);

2. 关键注意事项

  • 数据类型匹配:roles.{userEmail}是字符串类型(如'viewer'),而非数组,因此不能使用array-contains(该操作符仅用于匹配数组中的元素)。
  • 规则与查询的兼容性:Firestore要求查询条件必须能让服务器提前筛选出符合安全规则的文档。你的安全规则检查用户邮箱对应的角色是否在指定数组中,查询使用in操作符匹配相同的角色数组,两者逻辑对齐后才能通过权限验证。
  • 避免空值问题:必须确保currentUser?.email不为空,否则会生成无效的查询路径(如roles.undefined),直接导致权限错误或查询失败。

3. 额外优化建议

如果后续角色类型可能扩展,建议将角色列表抽成常量,避免重复编写:

const ALLOWED_ROLES = ['owner', 'admin', 'member', 'viewer'];

// 安全规则中同步使用该常量(需在规则内定义对应常量)
// 查询中直接调用
where(`roles.${userEmail}`, 'in', ALLOWED_ROLES)

内容的提问来源于stack exchange,提问作者Karthik Nagaraj

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 17:30:56