Firebase Firestore 规则并不总是适用于网络



考虑以下规则:

match /triplogs/{anyDocument} {
allow create: if request.auth != null;
allow read, update, delete: if request.auth.uid == resource.data.userId;
}

如果我的登录用户达到了这个标准,我就会得到标准:

错误:FirebaseError:[code=permission denied]:缺少或权限不足。

需要了解的几点:

  1. 我确实登录了,我可以输出当前用户的UID,这是正确的
  2. 我可以通过手机版找到同样的路线,而且它很有效
  3. 如果我删除了resource.data.userId检查,只检查用户是否通过了身份验证(甚至硬编码uid(,它就可以工作了(所以规则似乎得到了适当的检查(

模拟器说";资源";为null。我不明白resources对象怎么会为null,也许是模拟器的问题?

任何帮助都将不胜感激,我已经解决了问题,并在谷歌上搜索了过去的几个小时,但没有成功。

有问题的查询:

// ... My firebase wrapper:
import { firebaseApp } from '../utils/firebase';
// ...
const collectionName = 'triplogs';
export const fetchTrips = async (filters?: Filter[]) => {
let query;
const ref = db?.collection(collectionName);
const trips: TripLog[] = [];
if (filters) {
filters.forEach((filter) => {
query = ref?.where(filter.field, filter.operator, filter.value);
});
}
try {
const obj = query || ref;
console.log(firebaseApp()?.auth().currentUser?.uid); // <-- this is populated with my logged in UID, FWIW
const docs = await obj?.get();
docs?.forEach((doc) => {
const data = doc.data() as TripLog;
trips.push({
...data,
id: doc.id
});
});
return trips;
} catch (err) {
throw new Error(err);
}
};

以下是当我试图在模拟器中运行一个示例请求时的信息,与那些身份验证规则相反:

{
"path": "/databases/%28default%29/documents/triplogs/%7BanyDocument%7D"
"method": "get"
"auth": {
"uid": "5ompaySrXQcL9veWr3QlSujwlDS2"
"token": {
"sub": "5ompaySrXQcL9veWr3QlSujwlDS2"
"aud": "....omitted"
"firebase": {
"sign_in_provider": "google.com"
}
"email": "...omitted..."
"email_verified": true
"phone_number": ""
"name": "...."
}
}
"time": "2020-10-30T16:48:39.601Z"
}

sim中的错误为:

Error: simulator.rules line [32], column [58]. Null value error.

^^哪个是资源对象

如果我将身份验证规则更改为如下,那么我将返回数据

allow read, update, delete: if request.auth.uid != null;

数据如:

[{
"createdAt": 1597527979495,
"name": "Foo Bar Trip",
"date": 1597527979495,
"userId": "5ompaySrXQcL9veWr3QlSujwlDS2",
"id": "FnH2E9WfDkpRHPLXxlDy"
}]

但一旦我对照字段进行检查;资源";对象为空

allow read, update, delete: if request.auth.uid == resource.data.userId;

我会注意到您似乎在查询集合,但您的规则似乎是为文档编写的。。。如上所述,规则不是过滤器,它们不会分离集合中的单个文档。你在你的过滤器[数组]中这样做了吗?

不知道还会发生什么,但你对过滤器数组的处理(我也做了类似的事情(不会起作用-你在每个循环上重复查询,而不是扩展它。你可以尝试

query = ref;
if (filters) {
filters.forEach((filter) => {
query = query?.where(filter.field, filter.operator, filter.value);
});
}

以扩展查询。

此外,除非你的包装比它显示的要多,否则你的行:

const docs = await obj?.get();

"得到";QuerySnapshot,而不是文档数组。你必须做

const docs = await obj?.get().docs;

以获取实际文档的数组。

最后,我们不知道(从您的上述片段中(userID字段是否存在于您的Firestore文档中

解决方案

我想明白了。我错误地认为我正在进行的查询是由身份验证规则自动筛选的(在本例中为request.auth.id===userId(。。。但是firestore的auth中间件不能做到这一点。有道理。所以我只是添加了我的过滤器。。。像这样的东西:

fetchTrips([{
field: 'userId',
operator: '==',
value: user.uid,
}]);

这会起作用并返回正确的结果。试图正确更改用户ID也会引发身份验证错误。就是这样。

最新更新