在Firestore规则中声明函数

时间:2019-06-04 11:17:07

标签: firebase google-cloud-firestore firebase-security-rules

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

首先,这是我在Firestore数据库中拥有的数据结构的示例:

userProfiles/userId/userData

companies/companyId/companyData

看起来很简单。每个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
    }
  }
}

基于我将要拥有更多规则的事实,我想使它们更具可读性和重用性。根据此official guide,我可以创建自定义函数,并根据此article,它们可以是通用的,并且可以在主要规则框外声明。

我重构了规则,使其看起来像这样,并且对我也有效

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
    } 
  }
}

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

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
}

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

因此问题是:是否可以像我在示例中所做的那样将函数移到外部?我在这里有明显的错误吗?有没有更好的方法可以使我的规则更加明确?

P.S。 我还尝试将一些参数传递给该函数,包括用户名和公司ID-不用运气。

2 个答案:

答案 0 :(得分:1)

这是不可能的,规则仅在定义的范围内起作用,它们非常巧妙地提到了here

答案 1 :(得分:1)

可以在规则文件中的任何级别上定义功能。但是它们只能访问在定义它们的作用域中定义的变量。您还必须将其他任何内容作为变量传递。

因此,此(无用的)函数在全局定义时有效:

function isTrue() {
  return true;
}

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

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

我有时要做的是在函数定义中添加一个参数:

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

,然后将变量传递给调用:

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