ios - 无法在 Firebase 数据库 iOS 中保存用户
问题描述
我已经开发了一个 Instagram 应用程序克隆并在 Firebase 中注册了该应用程序,生成并添加了“GoogleService Plist”。我在模拟器中成功运行了应用程序,但是当我尝试通过应用程序注册时,它显示:
2020-04-17 18:24:41.154861+0530 IrinaGram[47884:2232371] 5.8.0 - [Firebase/Database][I-RDB038012] updateChildValues: at /users failed: permission_denied
Failed to upload user to database: Error Domain=com.firebase Code=1 "Permission denied" UserInfo={NSLocalizedDescription=Permission denied}
以下代码用于 FireBase 添加用户、喜欢、评论等
import Foundation
import Firebase
extension Auth {
func createUser(withEmail email: String, username: String, password: String, image: UIImage?, completion: @escaping (Error?) -> ()) {
Auth.auth().createUser(withEmail: email, password: password, completion: { (user, err) in
if let err = err {
print("Failed to create user:", err)
completion(err)
return
}
guard let uid = user?.user.uid else { return }
if let image = image {
Storage.storage().uploadUserProfileImage(image: image, completion: { (profileImageUrl) in
self.uploadUser(withUID: uid, username: username, profileImageUrl: profileImageUrl) {
completion(nil)
}
})
} else {
self.uploadUser(withUID: uid, username: username) {
completion(nil)
}
}
})
}
private func uploadUser(withUID uid: String, username: String, profileImageUrl: String? = nil, completion: @escaping (() -> ())) {
var dictionaryValues = ["username": username]
if profileImageUrl != nil {
dictionaryValues["profileImageUrl"] = profileImageUrl
}
let values = [uid: dictionaryValues]
Database.database().reference().child("users").updateChildValues(values, withCompletionBlock: { (err, ref) in
if let err = err {
print("Failed to upload user to database:", err)
return
}
completion()
})
}
}
extension Storage {
fileprivate func uploadUserProfileImage(image: UIImage, completion: @escaping (String) -> ()) {
guard let uploadData = image.jpegData(compressionQuality: 1) else { return } //changed from 0.3
let storageRef = Storage.storage().reference().child("profile_images").child(NSUUID().uuidString)
storageRef.putData(uploadData, metadata: nil, completion: { (_, err) in
if let err = err {
print("Failed to upload profile image:", err)
return
}
storageRef.downloadURL(completion: { (downloadURL, err) in
if let err = err {
print("Failed to obtain download url for profile image:", err)
return
}
guard let profileImageUrl = downloadURL?.absoluteString else { return }
completion(profileImageUrl)
})
})
}
fileprivate func uploadPostImage(image: UIImage, filename: String, completion: @escaping (String) -> ()) {
guard let uploadData = image.jpegData(compressionQuality: 1) else { return } //changed from 0.5
let storageRef = Storage.storage().reference().child("post_images").child(filename)
storageRef.putData(uploadData, metadata: nil, completion: { (_, err) in
if let err = err {
print("Failed to upload post image:", err)
return
}
storageRef.downloadURL(completion: { (downloadURL, err) in
if let err = err {
print("Failed to obtain download url for post image:", err)
return
}
guard let postImageUrl = downloadURL?.absoluteString else { return }
completion(postImageUrl)
})
})
}
}
extension Database {
//MARK: Users
func fetchUser(withUID uid: String, completion: @escaping (User) -> ()) {
Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
guard let userDictionary = snapshot.value as? [String: Any] else { return }
let user = User(uid: uid, dictionary: userDictionary)
completion(user)
}) { (err) in
print("Failed to fetch user from database:", err)
}
}
func fetchAllUsers(includeCurrentUser: Bool = true, completion: @escaping ([User]) -> (), withCancel cancel: ((Error) -> ())?) {
let ref = Database.database().reference().child("users")
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionaries = snapshot.value as? [String: Any] else {
completion([])
return
}
var users = [User]()
dictionaries.forEach({ (key, value) in
if !includeCurrentUser, key == Auth.auth().currentUser?.uid {
completion([])
return
}
guard let userDictionary = value as? [String: Any] else { return }
let user = User(uid: key, dictionary: userDictionary)
users.append(user)
})
users.sort(by: { (user1, user2) -> Bool in
return user1.username.compare(user2.username) == .orderedAscending
})
completion(users)
}) { (err) in
print("Failed to fetch all users from database:", (err))
cancel?(err)
}
}
func isFollowingUser(withUID uid: String, completion: @escaping (Bool) -> (), withCancel cancel: ((Error) -> ())?) {
guard let currentLoggedInUserId = Auth.auth().currentUser?.uid else { return }
Database.database().reference().child("following").child(currentLoggedInUserId).child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
if let isFollowing = snapshot.value as? Int, isFollowing == 1 {
completion(true)
} else {
completion(false)
}
}) { (err) in
print("Failed to check if following:", err)
cancel?(err)
}
}
func followUser(withUID uid: String, completion: @escaping (Error?) -> ()) {
guard let currentLoggedInUserId = Auth.auth().currentUser?.uid else { return }
let values = [uid: 1]
Database.database().reference().child("following").child(currentLoggedInUserId).updateChildValues(values) { (err, ref) in
if let err = err {
completion(err)
return
}
let values = [currentLoggedInUserId: 1]
Database.database().reference().child("followers").child(uid).updateChildValues(values) { (err, ref) in
if let err = err {
completion(err)
return
}
completion(nil)
}
}
}
func unfollowUser(withUID uid: String, completion: @escaping (Error?) -> ()) {
guard let currentLoggedInUserId = Auth.auth().currentUser?.uid else { return }
Database.database().reference().child("following").child(currentLoggedInUserId).child(uid).removeValue { (err, _) in
if let err = err {
print("Failed to remove user from following:", err)
completion(err)
return
}
Database.database().reference().child("followers").child(uid).child(currentLoggedInUserId).removeValue(completionBlock: { (err, _) in
if let err = err {
print("Failed to remove user from followers:", err)
completion(err)
return
}
completion(nil)
})
}
}
//MARK: Posts
func createPost(withImage image: UIImage, caption: String, completion: @escaping (Error?) -> ()) {
guard let uid = Auth.auth().currentUser?.uid else { return }
let userPostRef = Database.database().reference().child("posts").child(uid).childByAutoId()
guard let postId = userPostRef.key else { return }
Storage.storage().uploadPostImage(image: image, filename: postId) { (postImageUrl) in
let values = ["imageUrl": postImageUrl, "caption": caption, "imageWidth": image.size.width, "imageHeight": image.size.height, "creationDate": Date().timeIntervalSince1970, "id": postId] as [String : Any]
userPostRef.updateChildValues(values) { (err, ref) in
if let err = err {
print("Failed to save post to database", err)
completion(err)
return
}
completion(nil)
}
}
}
func fetchPost(withUID uid: String, postId: String, completion: @escaping (Post) -> (), withCancel cancel: ((Error) -> ())? = nil) {
guard let currentLoggedInUser = Auth.auth().currentUser?.uid else { return }
let ref = Database.database().reference().child("posts").child(uid).child(postId)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let postDictionary = snapshot.value as? [String: Any] else { return }
Database.database().fetchUser(withUID: uid, completion: { (user) in
var post = Post(user: user, dictionary: postDictionary)
post.id = postId
//check likes
Database.database().reference().child("likes").child(postId).child(currentLoggedInUser).observeSingleEvent(of: .value, with: { (snapshot) in
if let value = snapshot.value as? Int, value == 1 {
post.likedByCurrentUser = true
} else {
post.likedByCurrentUser = false
}
Database.database().numberOfLikesForPost(withPostId: postId, completion: { (count) in
post.likes = count
completion(post)
})
}, withCancel: { (err) in
print("Failed to fetch like info for post:", err)
cancel?(err)
})
})
})
}
func fetchAllPosts(withUID uid: String, completion: @escaping ([Post]) -> (), withCancel cancel: ((Error) -> ())?) {
let ref = Database.database().reference().child("posts").child(uid)
ref.observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionaries = snapshot.value as? [String: Any] else {
completion([])
return
}
var posts = [Post]()
dictionaries.forEach({ (postId, value) in
Database.database().fetchPost(withUID: uid, postId: postId, completion: { (post) in
posts.append(post)
if posts.count == dictionaries.count {
completion(posts)
}
})
})
}) { (err) in
print("Failed to fetch posts:", err)
cancel?(err)
}
}
func deletePost(withUID uid: String, postId: String, completion: ((Error?) -> ())? = nil) {
Database.database().reference().child("posts").child(uid).child(postId).removeValue { (err, _) in
if let err = err {
print("Failed to delete post:", err)
completion?(err)
return
}
Database.database().reference().child("comments").child(postId).removeValue(completionBlock: { (err, _) in
if let err = err {
print("Failed to delete comments on post:", err)
completion?(err)
return
}
Database.database().reference().child("likes").child(postId).removeValue(completionBlock: { (err, _) in
if let err = err {
print("Failed to delete likes on post:", err)
completion?(err)
return
}
Storage.storage().reference().child("post_images").child(postId).delete(completion: { (err) in
if let err = err {
print("Failed to delete post image from storage:", err)
completion?(err)
return
}
})
completion?(nil)
})
})
}
}
func addCommentToPost(withId postId: String, text: String, completion: @escaping (Error?) -> ()) {
guard let uid = Auth.auth().currentUser?.uid else { return }
let values = ["text": text, "creationDate": Date().timeIntervalSince1970, "uid": uid] as [String: Any]
let commentsRef = Database.database().reference().child("comments").child(postId).childByAutoId()
commentsRef.updateChildValues(values) { (err, _) in
if let err = err {
print("Failed to add comment:", err)
completion(err)
return
}
completion(nil)
}
}
func fetchCommentsForPost(withId postId: String, completion: @escaping ([Comment]) -> (), withCancel cancel: ((Error) -> ())?) {
let commentsReference = Database.database().reference().child("comments").child(postId)
commentsReference.observeSingleEvent(of: .value, with: { (snapshot) in
guard let dictionaries = snapshot.value as? [String: Any] else {
completion([])
return
}
var comments = [Comment]()
dictionaries.forEach({ (key, value) in
guard let commentDictionary = value as? [String: Any] else { return }
guard let uid = commentDictionary["uid"] as? String else { return }
Database.database().fetchUser(withUID: uid) { (user) in
let comment = Comment(user: user, dictionary: commentDictionary)
comments.append(comment)
if comments.count == dictionaries.count {
comments.sort(by: { (comment1, comment2) -> Bool in
return comment1.creationDate.compare(comment2.creationDate) == .orderedAscending
})
completion(comments)
}
}
})
}) { (err) in
print("Failed to fetch comments:", err)
cancel?(err)
}
}
//MARK: Utilities
func numberOfPostsForUser(withUID uid: String, completion: @escaping (Int) -> ()) {
Database.database().reference().child("posts").child(uid).observeSingleEvent(of: .value) { (snapshot) in
if let dictionaries = snapshot.value as? [String: Any] {
completion(dictionaries.count)
} else {
completion(0)
}
}
}
func numberOfFollowersForUser(withUID uid: String, completion: @escaping (Int) -> ()) {
Database.database().reference().child("followers").child(uid).observeSingleEvent(of: .value) { (snapshot) in
if let dictionaries = snapshot.value as? [String: Any] {
completion(dictionaries.count)
} else {
completion(0)
}
}
}
func numberOfFollowingForUser(withUID uid: String, completion: @escaping (Int) -> ()) {
Database.database().reference().child("following").child(uid).observeSingleEvent(of: .value) { (snapshot) in
if let dictionaries = snapshot.value as? [String: Any] {
completion(dictionaries.count)
} else {
completion(0)
}
}
}
func numberOfLikesForPost(withPostId postId: String, completion: @escaping (Int) -> ()) {
Database.database().reference().child("likes").child(postId).observeSingleEvent(of: .value) { (snapshot) in
if let dictionaries = snapshot.value as? [String: Any] {
completion(dictionaries.count)
} else {
completion(0)
}
}
}
}
我也在 Firebase 数据库中添加了权限:
请告诉我哪里错了,我必须做什么来解决这个问题。我需要在 Firebase 中手动添加子节点吗?如果是,那么请指导步骤。我对 FireBase 数据库的了解非常少,而且我仍处于学习阶段。任何帮助将不胜感激
解决方案
将以下代码替换为您的 Firebase 规则部分:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
推荐阅读
- node.js - 使用 Mongo 和 Mongoose 对无限滚动进行排序
- javascript - Served HTML Table 不会在不重新启动服务器的情况下更改内容
- ffmpeg - 使用 Microsoft Visual Studio 2017 预览版为 windows10/aarch64 编译 FFmpeg 时出错
- asynchronous - 是否可以控制 Scalatest 的异步测试用例的执行?
- awk - 是否可以不匹配转义的 FS 字符?
- python - pytorch 使用索引列表修改数组
- sql - 在 Bootstrap 模式中显示 SQL 表数据
- vue.js - 如何为从 .vue 中的别名导入的模块方法获取智能感知
- asp.net-core - 约束引用“slugify”无法解析为类型
- java - 如何从 List 创建 HashSet