我正在構建一個使用Firebase的電子郵件和密碼登錄功能的應用程序。我讓用戶使用用戶名,電子郵件和密碼進行註冊。如果用戶名不是唯一的,我正在努力阻止用戶被創建。我一直在閱讀其他問題(特別是Firebase-android-make-username-unique和how-prevent-username-from-duplicate-signup-infirebase),但我還沒有得到它充分的工作。Firebase iOS Swift:防止重複的用戶名
我跟着上面的第一個鏈接的指示,成立了我的數據結構爲:
app : {
users: {
"some-user-uid": {
email: "[email protected]"
username: "myname"
}
},
usernames: {
"myname": "some-user-uid"
}
}
和我的安全規則:
"users": {
"$uid": {
".write": "auth !== null && auth.uid === $uid",
".read": "auth !== null && auth.provider === 'password'",
"username": {
".validate": "
!root.child('usernames').child(newData.val()).exists() ||
root.child('usernames').child(newData.val()).val() == $uid"
}
}
}
採用這種設置,如果我嘗試創建一個用戶名已經存在的新用戶,它會阻止用戶被添加到我的數據結構中。當下面的代碼被調用時,如果用戶名是重複的,它會輸出「用戶數據無法保存」。
func createNewAccount(uid: String, user: Dictionary<String, String>) {
USER_REF.childByAppendingPath(uid).setValue(user, withCompletionBlock: {
(error:NSError?, ref:Firebase!) in
if (error != nil) {
print("User Data could not be saved.")
} else {
print("User Data saved successfully!")
}
})
}
func addUsernameToUsernamePath (userData: Dictionary<String, String>) {
USERNAME_REF.updateChildValues(userData)
}
這裏是我卡住的地方。我的create account方法在調用createUser和authUser(我需要獲得uid)之前不會調用上述兩種方法。我的問題是,用戶仍然被創建爲註冊用戶,我的安全規則只是保持用戶信息不被添加到我的數據結構中。如果有重複的用戶名,我需要弄清楚如何阻止用戶被創建。
@IBAction func createAccount() {
let username = usernameField.text
let email = emailField.text
let password = passwordField.text
if username != "" && email != "" && password != "" {
// Set Email and Password for the New User.
DataService.dataService.BASE_REF.createUser(email, password: password, withValueCompletionBlock: { error, result in
if error != nil {
print("Error: \(error)")
if let errorCode = FAuthenticationError(rawValue: error.code) {
switch (errorCode) {
case .EmailTaken:
self.signupErrorAlert("Email In Use", message: "An account has already been created for this email address.")
default:
self.signupErrorAlert("Oops!", message: "Having some trouble creating your account. Please try again or check your internet connection.")
}
}
} else {
DataService.dataService.BASE_REF.authUser(email, password: password, withCompletionBlock: {
err, authData in
let user = ["provider": authData.provider!, "email": email!, "username": username!]
let userData = [username!: authData.uid!]
DataService.dataService.createNewAccount(authData.uid, user: user)
DataService.dataService.addUsernameToUsernamePath(userData)
})
編輯
這裏是解決我的問題我更新的createAccount方法。
@IBAction func createAccount() {
let username = usernameField.text
let email = emailField.text
let password = passwordField.text
if username != "" && email != "" && password != "" {
DataService.dataService.USERNAME_REF.observeEventType(.Value, withBlock: { snapshot in
var usernamesMatched = false
if snapshot.value is NSNull {
usernamesMatched = false
} else {
let usernameDictionary = snapshot.value
let usernameArray = Array(usernameDictionary.allKeys as! [String])
for storedUserName in usernameArray {
if storedUserName == self.usernameField.text! {
usernamesMatched = true
self.signupErrorAlert("Username Already Taken", message: "Please try a different username")
}
}
}
if !usernamesMatched {
// Set Email and Password for the New User.
DataService.dataService.BASE_REF.createUser(email, password: password, withValueCompletionBlock: { error, result in
if error != nil {
print("Error: \(error)")
if let errorCode = FAuthenticationError(rawValue: error.code) {
switch (errorCode) {
case .EmailTaken:
self.signupErrorAlert("Email In Use", message: "An account has already been created for this email address.")
default:
self.signupErrorAlert("Oops!", message: "Having some trouble creating your account. Please try again or check your internet connection.")
}
}
} else {
// Create and Login the New User with authUser
DataService.dataService.BASE_REF.authUser(email, password: password, withCompletionBlock: {
err, authData in
let user = ["provider": authData.provider!, "email": email!, "username": username!]
let userData = [username!: authData.uid!]
// Seal the deal in DataService.swift.
DataService.dataService.createNewAccount(authData.uid, user: user)
DataService.dataService.addUsernameToUsernamePath(userData)
})
在調用createUser()之前驗證用戶名不存在? – Kato
感謝您的建議。我只是更新了我的代碼,它似乎解決了這個問題。 – chickenparm
爲什麼你不是首先通過createUser-> FAuthenticationErrorEmailTaken檢查重複的用戶用戶名,如果它可用,然後在/ users節點中創建用戶?如果您這樣做,您可以將該代碼縮減爲幾行,因爲該用戶名已保證不會存在於/ users節點中。 – Jay