【发布时间】:2016-05-10 00:14:24
【问题描述】:
我正在构建一个使用 Firebase 的电子邮件和密码登录功能的应用。我让用户使用用户名、电子邮件和密码进行注册。如果用户名不是唯一的,我正在努力如何阻止创建用户。我一直在阅读其他问题(特别是 Firebase-android-make-username-unique 和 how-prevent-username-from-duplicate-signup-infirebase),但我仍然没有让它完全发挥作用。
我按照上面第一个链接中的说明将我的数据结构设置为:
app : {
users: {
"some-user-uid": {
email: "test@test.com"
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)
}
这就是我卡住的地方。我下面的创建帐户方法在调用 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() 之前验证用户名不存在?
-
感谢您的建议。我刚刚更新了我的代码,它似乎已经解决了这个问题。
-
为什么不先通过createUser->FAuthenticationErrorEmailTaken 检查重复的用户用户名,如果可用,然后在/users 节点中创建用户?如果您这样做,您可以将该代码减少到几行,因为该用户名保证不存在于您的 /users 节点中。
-
检查重复的电子邮件地址。 createUser 只有电子邮件和密码的参数。我还在为每个用户创建一个用户名。在我的应用程序中,我让用户输入用户名、电子邮件和密码来创建帐户。我不相信 createUser 有办法检查重复的用户名。我确实设置了 FAuthenticationErrorEmailTaken 来检查重复的电子邮件地址。