我具有以下文档层次结构: / organizations / {orgId} / classes / {classId} / students / {studentId}
想法是班级文档中有一个TeacherUid字段,该字段当前存储分配给班级的老师的Uid。只有一位老师或管理员才能阅读/创建/编辑班上的学生。 *请注意,我只是测试老师的阅读,遇到了这个障碍,之后我将对创建/更新权限应用相同的规则。
我有以下firestore.rules:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /organizations/{orgId} {
allow read: if isAdmin();
allow create,update: if isAdmin();
match /classes/{classId} {
allow read: if request.auth.uid != null;
allow create,update: if isAdmin();
match /students/{studentId} {
allow read: if isAdmin() || belongsToCurrentClass();
allow create,update: if isAdmin();
}
}
}
}
}
function isAdmin() {
// Removed for security. isAdmin routine currently works correctly
}
function belongsToCurrentClass() {
// returns true if the authenticated user is the teacher of the requested class
return get(/databases/$(database)/documents/organizations/$(orgId)/classes/$(classId)).data.teacherUid == request.auth.uid;
}
这似乎不起作用。虽然它正确地允许管理员读取/创建/编辑,但不允许具有相同的request.auth.uid的已认证用户读取,该请求与存储在父类文档中的TeacherUid值相同。
我已经使用在线Firebase控制台Firestore模拟器以及运行本地的Firestore模拟器运行的mocha单元测试进行了测试。
我似乎无法弄清楚问题是什么。
这是我的test.js文档的相关部分:
const fs = require('fs');
const path = require('path');
const TEST_FIREBASE_PROJECT_ID = 'test-firestore-rules-project';
const firebase = require('@firebase/testing');
const authTeacher = {
uid: 'testTeacher1',};
const authAdmin = {
// Removed for security
};
before(async () => {
// The above was from the codelab. Commenting out the below since we aren't testing rules at this moment.
const rulesContent = fs.readFileSync(path.resolve(__dirname,'../../firestore.rules'));
await firebase.loadFirestoreRules({
projectId: TEST_FIREBASE_PROJECT_ID,rules: rulesContent,});
});
after(() => {
firebase.apps().forEach(app => app.delete());
});
...
describe('Classes/Students/* rules',() => {
const testClasspath = 'organizations/testOrg/classes/testClass';
const testStudentPath = testClasspath + '/students/testStudent';
const newStudentPath = testClasspath + '/students/newStudent';
const testOtherClasspath = 'organizations/testOrg/classes/testClass';
const testOtherStudentPath = testOtherClasspath + '/students/testOtherStudent';
const newOtherStudentPath = testOtherClasspath + '/students/newOtherStudent';
const dbUnauth = firebase
.initializeTestApp({
projectId: TEST_FIREBASE_PROJECT_ID,})
.firestore();
const dbTeacher = firebase
.initializeTestApp({
projectId: TEST_FIREBASE_PROJECT_ID,auth: authTeacher,})
.firestore();
const dbAdmin = firebase
.initializeTestApp({
projectId: TEST_FIREBASE_PROJECT_ID,auth: authAdmin,})
.firestore();
before(async () => {
const admin = firebase
.initializeAdminApp({
projectId: TEST_FIREBASE_PROJECT_ID,})
.firestore();
// Create Class - for testing classes that belong to the authenticated user
await admin.doc(testClasspath).set({
teacherUid: authTeacher.uid,});
// Create Student
await admin.doc(testStudentPath).set({
name: 'John Smith',});
// Create Other Class - for testing classes that belong to other users
await admin.doc(testOtherClasspath).set({
teacherUid: 'someOtherTeacherUid',});
// Create Other Student
await admin.doc(testOtherStudentPath).set({
name: 'Cave Johnson',});
});
after(() => {
// Clear data from the emulator
firebase.clearFirestoreData({ projectId: TEST_FIREBASE_PROJECT_ID });
});
it('Unauthenticated users cannot access students',async () => {
await firebase.assertFails(dbUnauth.doc(testStudentPath).get());
});
it('Unauthenticated users cannot create students',async () => {
await firebase.assertFails(
dbUnauth.doc(newStudentPath).set({
name: 'Jane Doe',})
);
});
it('Non-admin users can read students',async () => {
await firebase.assertSucceeds(dbTeacher.doc(testStudentPath).get());
});
it('Non-admin users cannot read students from another user',async () => {
await firebase.assertFails(dbTeacher.doc(testOtherStudentPath).get());
});
it('Non-admin users can edit students',async () => {
await firebase.assertSucceeds(
dbTeacher.doc(testStudentPath).set({
anotherProperty: 'Some Value',})
);
});
it('Non-admin users cannot edit students from another user',async () => {
await firebase.assertFails(
dbTeacher.doc(testOtherStudentPath).set({
anotherProperty: 'Some Value',})
);
});
it('Non-admin users can create students',async () => {
await firebase.assertSucceeds(
dbTeacher.doc(newStudentPath).set({
name: 'Jane Doe',})
);
});
it('Non-admin users cannot create students in a class they do not belong to',async () => {
await firebase.assertFails(
dbTeacher.doc(testOtherStudentPath).set({
name: 'Jane Doe',})
);
});
it('Non-admin users cannot delete students',async () => {
await firebase.assertFails(dbTeacher.doc(testStudentPath).delete());
});
it('Admin users can read students',async () => {
await firebase.assertSucceeds(dbAdmin.doc(testStudentPath).get());
});
it('Admin users can create students',async () => {
await firebase.assertSucceeds(
dbAdmin.doc(newStudentPath).set({
name: 'Jane Doe',})
);
});
it('Admin users can edit students',async () => {
await firebase.assertSucceeds(
dbAdmin.doc(testStudentPath).set({
anotherProperty: 'Some Value',})
);
});
it('Admin users cannot delete students',async () => {
await firebase.assertFails(dbAdmin.doc(testStudentPath).delete());
});
});
这是运行单元测试时的错误输出:
PS C:\Local\Personal\Angular Projects\TSI\functions> npm test
> functions@ test C:\Local\Personal\Angular Projects\TSI\functions
> mocha
Organization rules
√ Unauthenticated users cannot read organizations (48ms)
√ Unauthenticated users cannot create orgs organizations
√ Unauthenticated users cannot delete organizations
√ Non-admin users cannot read organizations (45ms)
√ Non-admin users cannot edit organizations
√ Non-admin users cannot create organizations
√ Non-admin users cannot delete organizations
√ Admin users can read organizations (47ms)
√ Admin users can create organizations
√ Admin users can edit organizations
√ Admin users cannot delete organizations
Classes rules
√ Unauthenticated users cannot access classes
√ Unauthenticated users cannot create classes
√ Unauthenticated users cannot delete classes
√ Non-admin users can read classes (38ms)
√ Non-admin users cannot edit classes
√ Non-admin users cannot create classes
√ Non-admin users cannot delete classes
√ Admin users can read classes
√ Admin users can create classes
√ Admin users can edit classes
√ Admin users cannot delete classes
Classes/Students/* rules
√ Unauthenticated users cannot access students
√ Unauthenticated users cannot create students
1) Non-admin users can read students
√ Non-admin users cannot read students from another user
2) Non-admin users can edit students
√ Non-admin users cannot edit students from another user
3) Non-admin users can create students
√ Non-admin users cannot create students in a class they do not belong to
√ Non-admin users cannot delete students
√ Admin users can read students
√ Admin users can create students
√ Admin users can edit students
√ Admin users cannot delete students
32 passing (3s)
3 failing
1) Classes/Students/* rules
Non-admin users can read students:
FirebaseError:
Null value error. for 'get' @ L15
at new FirestoreError ...
2) Classes/Students/* rules
Non-admin users can edit students:
FirebaseError: 7 PERMISSION_DENIED:
false for 'update' @ L16
at new FirestoreError ...
3) Classes/Students/* rules
FirebaseError: 7 PERMISSION_DENIED:
false for 'create' @ L16
at new FirestoreError ...
npm ERR! Test failed. See above for more details.