在 Firestore 规则中声明函数

Art*_*pov 3 firebase firebase-security google-cloud-firestore

这是我现在面临的 Firestore 安全规则问题。

首先,这里是我的 firestore 数据库中的数据结构示例:

userProfiles/userId/userData

companies/companyId/companyData
Run Code Online (Sandbox Code Playgroud)

看起来很简单。每个userData包含和命名的数组companies,其中包含该用户有权访问的所有 companyId。

现在我需要编写规则以仅当 companyId 是特定用户信息公司列表时才允许读取 companyData。

以下是该规则的工作对我来说:

service cloud.firestore {
  match /databases/{database}/documents {
    match /companies/{companyId} {
      allow read: if companyId in get(/databases/$(database)/documents/userProfiles/$(request.auth.uid)).data.companies
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

考虑到我将有更多规则,我想让它们更具可读性和重用性。根据这个官方指南,我可以创建自定义函数,根据这篇文章,它们可以是通用的,并且可以在主要规则块之外声明。

我重构我的规则是这样的,它也是工作对我来说:

service cloud.firestore {
  match /databases/{database}/documents {
    match /companies/{companyId} {
      allow read: if companyId in getUserCompanies()
    }
    function getUserCompanies() {
        return get(/databases/$(database)/documents/userProfiles/$(request.auth.uid)).data.companies
    } 
  }
}
Run Code Online (Sandbox Code Playgroud)

但是现在我想将函数移到规则块之外以使其更加清晰:

service cloud.firestore {
  match /databases/{database}/documents {
    match /companies/{companyId} {
      allow read: if companyId in getUserCompanies()
    } 
  }
}

function getUserCompanies() {
    return get(/databases/$(database)/documents/userProfiles/$(request.auth.uid)).data.companies
}
Run Code Online (Sandbox Code Playgroud)

这是行不通的。没有任何错误,我只是收到Read denied来自模拟器的常规消息。

所以问题是:是否可以像我在示例中那样将函数移到外面?我在这里犯了什么明显的错误吗?有没有更好的方法让我的规则设置得更加清晰?

PS 我还尝试将一些参数传递给该函数,包括用户和公司 ID - 不走运。

Fra*_*len 9

可以在规则文件中的任何级别定义函数。但是他们只能访问在您定义它们的范围内定义的变量。您必须作为变量传入的任何其他内容。

所以这个(无用的)函数在全局定义时有效:

function isTrue() {
  return true;
}
Run Code Online (Sandbox Code Playgroud)

但是这个不会,因为它无法访问request

function isAdmin() {
  return (request.auth.token.email_verified && 
    request.auth.token.email.matches(".*@google.com"));
}
Run Code Online (Sandbox Code Playgroud)

我有时会在函数定义中添加一个参数:

function isAdmin(request) {
  return (request.auth.token.email_verified && 
    request.auth.token.email.matches(".*@google.com"));
}
Run Code Online (Sandbox Code Playgroud)

然后将变量传递给调用:

  allow update: if isAdmin(request) || 
    (request.auth.uid == uid && isUnmodified(request, resource, 'name'));
Run Code Online (Sandbox Code Playgroud)