У меня есть следующая иерархия документов: / organization / {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, а также запуска модульных тестов Mocha с помощью локального эмулятора FireStore.
Кажется, я не могу понять, в чем проблема.
Вот соответствующие части моего документа 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.