[英]Firestore: Delete document and security rules
I have a problem dealing with deletion using firestore. 我在使用Firestore处理删除时遇到问题。 In short, I created a security rule for posts like this:
简而言之,我为这样的帖子创建了安全规则:
First there are some functions in the rules: 首先,规则中有一些功能:
service cloud.firestore { 服务cloud.firestore {
function userRoles() {
return ['admin', 'customer', 'reader'];
}
function userGenders() {
return ['mal', 'female', 'other'];
}
function postVisibilities() {
return ['public', 'private', 'protected'];
}
function postType() {
return ['music', 'motion_design', 'graphic_art'];
}
function isPayment(paymentDoc) {
return paymentDoc != null
&& paymentDoc.date is timestamp
&& paymentDoc.price is number
&& paymentDoc.price is number
&& paymentDoc.price > 0;
}
function isBill(billDoc) {
return billDoc.sellerId is string
&& billDoc.buyerId is string
&& billDoc.postIds != null
&& billDoc.date is timestamp
&& billDoc.paymentDoc != null
&& isPayment(billDoc.paymentDoc);
}
function isAccount(accountDoc) {
return accountDoc.isRegistered is bool
&& accountDoc.addressId is string
&& accountDoc.contactId is string
&& accountDoc.email is string
&& accountDoc.username is string
&& accountDoc.gender is string
&& accountDoc.gender in userGenders()
&& accountDoc.role is string
&& accountDoc.role in userRoles();
}
function isPost(postDoc) {
return postDoc.createdAt is timestamp
&& postDoc.updatedAt is timestamp
&& postDoc.title is string
&& postDoc.text is string
&& postDoc.image is string
&& postDoc.authorId is string
&& postDoc.visibility is string
&& postDoc.visibility in postVisibilities();
}
function isVote(voteDoc) {
return voteDoc.authorId is string
&& voteDoc.reaction is string
&& voteDoc.reaction in ['up', 'down'];
}
function isComment(commentDoc) {
return commentDoc.authorId is string
&& commentDoc.message is string;
}
function isSingle(doc) {
return doc.size() == 1;
}
match /databases/{database}/documents {
function userExists(userId) {
return userId != null && exists(/databases/$(database)/documents/accounts/$(userId));
}
function getUserRole(userId) {
return get(/databases/$(database)/documents/accounts/$(userId)).data.roles;
}
function hatUserRole(userId, role) {
return getRoleForUser(userId) in role;
}
match /{document=**} {
allow read: if true;
allow write: if false;
}
match /accounts/{accountId} {
allow create: if isAccount(request.resource.data)
&& (request.auth.uid == accountId || hatUserRole(request.auth.uid, ['admin']));
allow update: if request.auth.uid == accountId || hatUserRole(request.auth.uid, ['admin']);
allow delete: if hatUserRole(request.auth.uid, ['admin']);
match /contacts/{contactId} {
allow write: if isSingle(request.resource.data)
&& request.auth.uid == accountId;
allow read: if userExists(request.auth.uid);
}
match /favorites/{favoriteId} {
allow write: if isSingle(request.resource.data)
&& request.auth.uid == accountId;
allow read: if userExists(request.auth.uid);
}
match /votes/{voteId} {
allow create: if isVote(request.resource.data)
&& userExists(request.auth.uid);
allow update: if userExists(request.auth.uid)
&& isVote(request.resource.data)
&& request.resource.data.authorId == request.auth.uid
allow delete: if userExists(request.auth.uid)
&& (request.auth.uid == accountId
|| hatUserRole(request.auth.uid, ['admin']))
}
}
match /bills/{billId} {
allow create: if isBill(request.resource.data)
&& userExists(request.resource.data.sellerId)
&& userExists(request.resource.data.buyerId)
&& (request.resource.data.buyerId == request.auth.uid
|| request.resource.data.sellerId == request.auth.uid);
allow update, delete: if false;
allow read: if request.resource.data.buyerId == request.aut.uid
|| request.resource.data.sellerId == request.aut.uid;
}
match /posts/{postId} {
function publicPost() {
return get(/databases/$(database)/documents/posts/$(postId)).data.visibility == 'public';
}
function postVisibility() {
return get(/databases/$(database)/documents/posts/$(postId)).data.visibility;
}
function protectedPost() {
return userExists(request.auth.uid)
&& get(/databases/$(database)/documents/posts/$(postId)).data.visibility == 'public';
}
function findPostAuthor(pathToFind) {
return get(/databases/$(database)/documents/posts/$(pathToFind)).data.authorId
}
allow create, update: if isPost(request.resource.data)
&& userExists(request.auth.uid)
&& request.resource.data.authorId == request.auth.uid;
allow read: if request.resource.data.visibility == 'public';
allow delete: if userExists(request.auth.uid)
&& findPostAuthor(request.resource.id) == request.auth.uid;
match /votes/{voteId} {
allow read: if protectedPost(postId)
|| publicPost(postId);
allow create: if isVote(request.resource.data)
&& postVisibility(postId) in ['public', 'protected']
&& userExists(request.auth.uid);
allow update: if isVote(request.resource.data)
&& request.resource.data.authorId == request.auth.uid;
allow delete: if userExists(request.auth.uid)
&& (request.auth.uid == request.resource.data.authorId
|| hatUserRole(request.auth.uid, ['admin']));
}
match /comments/{commentId} {
allow read: if protectedPost(postId) || publicPost(postId);
allow create: if isComment(request.resource.data)
&& postVisibility(postId) in ['public', 'protected']
&& userExists(request.auth.uid);
allow update: if isComment(request.resource.data)
&& request.resource.data.authorId == request.auth.uid;
allow delete: if userExists(request.auth.uid)
&& (request.auth.uid == request.resource.data.authorId
|| hatUserRole(request.auth.uid, ['admin']));
}
}
}
}
For creation and update, all work fine. 对于创建和更新,一切正常。
After that, I created two methods implementations to delete a document, the two of them using id
s which are: 之后,我创建了两个方法实现来删除文档,其中两个使用
id
:
public deletePost(postId: string): Observable<void> {
const postRef = this.db.collection('posts').doc(postId).ref;
return fromPromise(this.db.firestore.runTransaction((transaction => {
return transaction.get(postRef).then(snapshot => {
if (!snapshot.exists) {
this.snackBar.open('Post doesn\'t exist', 'close');
} else {
const auth = snapshot.data().authorId === this._userId;
if (auth) {
transaction.delete(postRef);
} else {
this.snackBar.open('You\' not allowed to do that!');
}
}
});
})));
}
using transactions, and: 使用交易,以及:
protected removeElement(elementId: string): Observable<any> {
return fromPromise(this.db.collection(this.dbCollection).doc(elementId).delete());
}
not using any transaction, simple deletion. 不使用任何交易,简单删除。
Neither of those method work. 这些方法都不起作用。
When using the first method, I get: 使用第一种方法时,我得到:
ERROR Error: Server responded with status
at new FirestoreError (index.cjs.js:346)
at T.<anonymous> (index.cjs.js:6901)
at Ab (index.js:23)
at T.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.g.dispatchEvent (index.js:21)
at te (index.js:66)
at ve (index.js:69)
at T.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.g.jb (index.js:67)
at T.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.g.Na (index.js:67)
at XMLHttpRequest.wrapFn (zone.js:1188)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
at Object.onInvokeTask (core.js:3815)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188)
at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:496)
at invokeTask (zone.js:1540)
at XMLHttpRequest.globalZoneAwareCallback (zone.js:1566)
and I get with the second one: 我得到第二个:
ERROR Error: Missing or insufficient permissions.
at new FirestoreError (index.cjs.js:346)
at index.cjs.js:7088
at W.<anonymous> (index.cjs.js:7033)
at Ab (index.js:23)
at W.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.g.dispatchEvent (index.js:21)
at Re.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.Re.Ca (index.js:98)
at ye.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.g.Oa (index.js:86)
at dd (index.js:42)
at ed (index.js:39)
at ad (index.js:37)
at L.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.g.Sa (index.js:36)
at L.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.g.nb (index.js:35)
at Ab (index.js:23)
at T.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.g.dispatchEvent (index.js:21)
at ve (index.js:68)
at T.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.g.jb (index.js:67)
at T.push../node_modules/@firebase/webchannel-wrapper/dist/index.js.g.Na (index.js:67)
at XMLHttpRequest.wrapFn (zone.js:1188)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:421)
at Object.onInvokeTask (core.js:3815)
at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:420)
at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:188)
at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:496)
at invokeTask (zone.js:1540)
at XMLHttpRequest.globalZoneAwareCallback (zone.js:1566)
Since I'm not sure if the problem where the problem is, I have some theories: 由于我不确定问题出在哪里,因此我有一些理论:
Maybe in the rules
, when I write 也许在
rules
,当我写
allow delete: if userExists(request.auth.uid) && findPostAuthor(request.resource.data.id) == request.auth.uid;
I think, that as I only looking directly at the document using it's Id
, the request.resource.data.id
mustn't contain anything. 我认为,因为我只使用
Id
直接查看文档,所以request.resource.data.id
不能包含任何内容。
I also thought, that if transactions
doesn't work, it may be because the way it actually works is really different from what we see on other transactions functions. 我还认为,如果
transactions
无效,那可能是因为transactions
实际方式与我们在其他交易功能上看到的方式确实不同。
As I'm using angularFire2
, this.db => AngularFirestore, this.dbCollection => 'posts' and in the structure of any post, there is a autorId
field which is a string. 当我使用
angularFire2
,this.db => AngularFirestore,this.dbCollection =>'posts',在任何帖子的结构中,都有一个autorId
字段,它是一个字符串。
For delete
, you need to compare request.auth.uid
to resource.data.uid
, not to request.resource.data.uid
. 对于
delete
,您需要将request.auth.uid
与resource.data.uid
进行比较,而不是request.resource.data.uid
。 For example: 例如:
match /bookmarks/{id} {
allow create: if request.resource.data.uid == request.auth.uid
allow read, delete: if resource.data.uid == request.auth.uid
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.