Swift中Firestore权限规则问题:用户无法访问自身数据
解决Firebase Firestore权限错误(Code=7)的方案
问题根源
你的Firestore规则要求用户只能访问文档ID等于自身UID的users集合文档,但当前代码存在两个核心问题:
- 创建用户数据时使用
addDocument()生成随机文档ID,而非用户UID,导致规则中的request.auth.uid == userId(userId对应文档ID)不匹配。 - 获取用户数据时调用
getDocuments()查询整个users集合,违反了规则中仅允许访问自身文档的限制。
修正步骤
1. 保持规则不变,调整数据结构
确保users集合的文档ID等于用户Firebase Auth的UID,你的规则逻辑本身是正确的,只需让数据结构匹配规则要求。
2. 修改Swift代码
创建用户数据(用UID作为文档ID)
func createUserData(userId: String, userEmail: String, completionHandler: @escaping (_ documentID: String?, _ userId: String?, _ userType: UserType?, _ tokensUsed: Int?) -> ()) { let db = Firestore.firestore() // 直接用用户UID作为文档ID,替代随机生成ID db.collection("users").document(userId).setData([ "userEmail": userEmail, "lastLogin": Date(), "tokensUsed": 0, "userType": "free" ]) { error in if let error = error { print(error) completionHandler(nil, nil, nil, nil) return } // 直接通过UID获取数据,无需遍历集合 self.getUserData(userId: userId) { documentID, userType, tokensUsed in completionHandler(documentID, userId, userType, tokensUsed) } } }
获取用户数据(直接访问UID对应文档)
func getUserData(userId: String, completionHandler: @escaping (_ documentID: String?, _ userType: UserType?, _ tokensUsed: Int?) -> ()) { let db = Firestore.firestore() // 直接访问当前用户UID对应的文档,避免全集合查询 db.collection("users").document(userId).getDocument { document, error in if let error = error { print(error) completionHandler(nil, nil, nil) return } guard let document = document, document.exists else { completionHandler(nil, nil, nil) return } let documentUserType = document["userType"] as? String ?? "free" let userType: UserType = documentUserType == "premium" ? .premium : .free let tokensUsed = document["tokensUsed"] as? Int ?? 0 completionHandler(document.documentID, userType, tokensUsed) } }
更新用户数据(操作当前用户的UID文档)
func updateUserData(userId: String, userEmail: String, userTokens: Int, userType: String) { let db = Firestore.firestore() // 直接通过UID更新文档,无需传入documentID db.collection("users").document(userId).updateData([ "userEmail": userEmail, "lastLogin": Date(), "tokensUsed": userTokens, "userType": userType ]) { error in if let error = error { print(error) } } }
3. 额外注意事项
- 调用方法前,确保已通过Firebase Auth获取到有效用户UID(
Auth.auth().currentUser?.uid),避免传入空值或错误ID。 - 移除原代码中
DispatchQueue.main.asyncAfter的超时逻辑,直接访问单个文档的响应速度足够快,无需超时兜底。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

