You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firestore写入权限不足问题求助:图片上传后无法保存文档

问题分析:Firestore写入权限不足错误

问题场景

我尝试将图片上传至Firebase Storage,随后写入Firestore数据库,但遇到了权限不足的错误。

实现代码

Swift上传与写入函数

func storeMarketplaceItem() {
        guard let userId = Auth.auth().currentUser?.uid else {
            print("user not authenticated")
            return
        }
        let db = Firestore.firestore()
        let storage = Storage.storage()
        let storageRef = storage.reference(forURL: "gs://garbage-separator.firebasestorage.app")
        
        //let storageRef = Storage.storage().reference()
        
        var uploadedImageURLs: [String] = []
        let dispatchGroup = DispatchGroup()
        let imageID = UUID().uuidString
        
        for image in selectedImages {
            dispatchGroup.enter()
            //let imageID = UUID().uuidString
            let imageRef = storageRef.child("marketplace/\(imageID).jpg")
            // Metadata with userId for Firebase Storage
            let metadata = StorageMetadata()
            metadata.contentType = "image/jpeg"  // Set content type for the image
            metadata.customMetadata = ["userId": userId]
            //metadata.customMetadata = ["ImageId": imageID]
            if let imageData = image.jpegData(compressionQuality: 0.5) {
                print("Uploading image to: marketplace/\(imageID).jpg")
                
                // Upload image to Firebase Storage
                imageRef.putData(imageData, metadata: metadata) { metadata, error in
                    if let error = error {
                        print("Image upload error: \(error.localizedDescription)")
                        dispatchGroup.leave()
                        return
                    }
                    
                    // Fetch the download URL of the uploaded image
                    imageRef.downloadURL { url, error in
                        if let error = error {
                            print("Failed to get URL: \(error.localizedDescription)")
                        } else if let url = url {
                            uploadedImageURLs.append(url.absoluteString)
                            print("Image uploaded successfully: \(url.absoluteString)")
                        }
                        dispatchGroup.leave()
                    }
                }
            } else {
                print("Image data conversion failed for image: \(imageID)")
                dispatchGroup.leave()
            }
            
        }
        
        // Ensure images are uploaded before saving to Firestore
        dispatchGroup.notify(queue: .main) {
            if uploadedImageURLs.isEmpty {
                print("No images uploaded, aborting item storage.")
                return
            }
            
            // Create a new item to save in Firestore
            let newItem = MarketItem(id: UUID().uuidString, name: name, description: description, price: price, imageURLs: uploadedImageURLs)
            var newItemData = [
                "id": newItem.id,
                "name": newItem.name,
                "description": newItem.description,
                "price": newItem.price,
                "imageURLs": newItem.imageURLs,
                "userId": Auth.auth().currentUser?.uid ?? ""
            ]
            let documentId = newItem.id
            print("Generated Document ID: \(documentId)")
            let itemRef = db.collection("marketplace").document(imageID)
            itemRef.getDocument { (document, error) in
                if let document = document, document.exists {
                    print("Document already exists.")
                } else {
                    // Document doesn't exist, proceed with saving the new item
                    itemRef.setData(newItemData) { error in
                        if let error = error {
                            print("Error saving item to Firestore: \(error.localizedDescription)")
                        } else {
                            print("Item successfully saved to Firestore!")
                            presentationMode.wrappedValue.dismiss()
                        }
                    }
                }
            }
            // Add userId to Firestore document data
           
            
            // Save item to Firestore
            
        }
    }
}

Firestore安全规则

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Allow read and write access to all documents for authenticated users
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
      
      // Allow access to the "uploadCounts" subcollection
      match /uploadCounts/{documentId} {
        allow read, write: if request.auth != null && request.auth.uid == userId;
      }
      
      // Allow read access to anyone
    match /marketplace/{documentId} {
      allow read, write: if request.auth != null; //&& request.auth.uid == request.resource.data.userId;
    }

    }
  }
}

错误信息

上传图片至:marketplace/98F348B5-5A95-43F0-A707-6782866F969B.jpg
图片上传成功:
marketplace%2F98F348B5-5A95-43F0-A707-6782866F969B.jpg?alt=media&token=4bb04ed4-8c3b-4814-810e-012e88ab03e1
生成的文档ID:9FA8CA52-5971-4A11-90FF-900F521F7644
10.29.0 - [FirebaseFirestore][I-FST000001] 监听marketplace/98F348B5-5A95-43F0-A707-6782866F969B查询失败:权限缺失或不足。
保存条目至Firestore时出错:权限缺失或不足。
10.29.0 - [FirebaseFirestore][I-FST000001] (null)
10.29.0 - [FirebaseFirestore][I-FST000001] 写入marketplace/98F348B5-5A95-43F0-A707-6782866F969B失败:权限缺失或不足。
10.29.0 - [FirebaseFirestore][I-FST000001] (null)

问题原因与解决方法

核心问题:安全规则层级错误

你的marketplace集合规则被嵌套在/users/{userId}的匹配规则内,Firestore会默认认为marketplace是users集合下的子集合,但实际代码中你是直接访问根级的marketplace集合,导致规则不匹配,触发权限验证失败。

修复步骤

  1. 调整安全规则结构,将marketplace规则移至users规则外部,作为根级集合规则:
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // 用户集合规则
    match /users/{userId} {
      allow read, write: if request.auth != null && request.auth.uid == userId;
      
      // 用户下的uploadCounts子集合规则
      match /uploadCounts/{documentId} {
        allow read, write: if request.auth != null && request.auth.uid == userId;
      }
    }

    // 根级marketplace集合规则
    match /marketplace/{documentId} {
      allow read, write: if request.auth != null;
    }
  }
}
  1. 可选优化:文档ID一致性
    代码中生成了newItem.id作为文档ID,但实际写入时用的是imageID,导致日志显示的文档ID与实际写入ID不一致(虽非权限错误原因,但易引发后续逻辑混乱),建议统一:
    将let itemRef = db.collection("marketplace").document(imageID)修改为let itemRef = db.collection("marketplace").document(documentId)。

内容的提问来源于stack exchange,提问作者sats

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:37:31