考虑以下规则:
match /triplogs/{anyDocument} {
allow create: if request.auth != null;
allow read, update, delete: if request.auth.uid == resource.data.userId;
}
如果我的登录用户达到了这个标准,我就会得到标准:
错误:FirebaseError:[code=permission denied]:缺少或权限不足。
需要了解的几点:
- 我确实登录了,我可以输出当前用户的UID,这是正确的
- 我可以通过手机版找到同样的路线,而且它很有效
- 如果我删除了
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也会引发身份验证错误。就是这样。