我正在尝试为 firestore 编写一条安全规则,它将 Resource.data.EIDSTRING 值与 request.auth.uid 用户的 app_users 集合中的 EIDSTRING 值进行比较。但是,我无法使规则评估为 true,并且通过调试 firestore 规则提供的位发现我没有成功从 app_users 集合中获取 EIDSTRING 字段。我有一个类似的函数,可以从集合中获取另一个字段,并且它工作没有问题。
这是规则文件,具体问题出在
match/user_contracts/{document}
:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Match app_users document
match /app_users/{userId} {
allow read: if request.auth != null && belongsTo(userId);
allow update: if isAdminOrSpecialist(userId) || (request.auth != null
&& belongsTo(userId)
&& !hasRestrictedFields()
);
allow create: if request.auth != null;
allow delete: if false;
}
match /user_contracts/{document} {
allow read: if hasContract(resource.data.EIDSTRING, request.auth.uid);
allow write: if false;
}
match /{document=**}{
allow read: if request.auth != null;
allow update: if false;
allow create: if false;
allow delete: if false;
}
function isAdminOrSpecialist(userId){
let role = get(/databases/$(database)/documents/app_users/$(userId)).data.role;
return role == 'admin' || role == 'specialist';
}
function hasContract(docEID, userId){
let userEID = get(/databases/$(database)/documents/app_users/$(userId)).data.EIDSTRING;
return debug(userEID) == debug(docEID);
}
function belongsTo(userId){
return request.auth.uid == userId
}
function hasRestrictedFields(){
return request.resource.data.diff(resource.data).affectedKeys().hasAny(['EIDSTRING','impersonatedGrower', 'role']);
}
}
}
这是我正在运行的测试:
test.only('Testing read rules for own contracts', async(t) =>{
const res = await clientReadContracts(fbClient, users.testuser, '26FA348932590C33C3DA6809705ABDFA817712D406A76E62');
if(res.success){
t.log(res.message);
t.pass();
}else{
t.log(res.message, res.Error);
t.fail();
}
})
以及执行读取的函数:
export async function clientReadContracts(
fbClient,
client,
EIDSTRING,
) {
const clientAdminAuth = clientFirebaseAuth.getAuth();
const clientAdminUser = await clientFirebaseAuth.signInWithEmailAndPassword(
clientAdminAuth,
client.email,
client.password
)
.then(async (userCredential) => {
return await userCredential.user;
});
try {
const db = clientFirestore.getFirestore(fbClient);
const collectionRef = clientFirestore.collection(db,'user_contracts');
const query = clientFirestore.query(
collectionRef,
clientFirestore.where('EIDSTRING', '==', EIDSTRING)
);
const querySnapshot = await clientFirestore.getDocs(query);
if (!querySnapshot.empty) {
const docSnapshot = querySnapshot.docs[0];
const docData = docSnapshot.data();
return { success: true, message: 'doc read', data: docData };
} else {
return { success: true, message: 'doc not found', data: '' };
}
} catch (err) {
return { success: false, message: 'failure', Error: err.code };
}
}
正如您所看到的
isAdminOrSpecialist()
函数的工作原理非常相似,我对此没有任何问题,使用 debug(role) 打印出角色没有问题。但是,通过 return debug(userEID) == debug(docEID)
,我只能得到 docEID
的打印输出,而不是 userEID
,就好像它未定义或为 null。
我在模拟器中目视验证了 request.auth.uid 与正确的文档匹配
EIDSTRING
:
关于 firestore 规则的信息并不多,所以我希望这里有人有更多这方面的经验。
我希望从用户相应的
EIDSTRING
文档中获取 app_users
字段,但通过调试它不会打印出来。因此该规则始终评估为 false。
如果将来有什么变化,请随意回答这个问题,但现在,我从这个 4 年前的问题中学到了一些东西:firestore 规则 get()/exists() 不起作用 模拟器仍然不能与
get(path)
和 exists(path)
完美配合。
我部署了我的规则并在 Playground 中进行了测试,它正确验证了该规则的 GET 请求。
这是一个愚蠢的疏忽,因为现在它使我无法测试与此类规则验证交互的模拟器中的任何安全性。
对于遇到此问题的任何人来说,在实际的 Firebase 项目中遵守规则游乐场可能会更简单。