我可以让Firebase使用用户名登录过程吗? [英] Can I make Firebase use a username login process?

查看:118
本文介绍了我可以让Firebase使用用户名登录过程吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想制作一个允许用户名登录的系统。此过程需要以下内容:

$ ol

  • 用户必须注册一个电子邮件/密码

  • 用户可以设置一个唯一的用户名

  • 用户可以使用电子邮件或用户名登录

  • 用户可以通过电子邮件或用户名恢复密码

  • 该功能必须在启用了持久性的数据库上工作

  • 以前已经回答过这个问题,功能为用户使用密码恢复。他们也没有处理大小写敏感的问题,一个人可以注册为史酷比,另一个人可以注册为史酷比。 解决方案

    经过多次迭代开发,我已经想出了以下设计来解决这个问题。我将在Swift中发布我的代码片段,但是它们通常可以直接转换成Android。





    1. 为电子邮件/密码创建Firebase注册流程。
    2. 的用户登录体验。这可以从
      需要注意的几件事:



      • 用户名存储两次,一次存储在用户名中,一次存储在 details / [uid] / username 。我建议这样做,因为它允许你用户名区分大小写(见下一点),它也允许你知道确切的数据库引用来检查用户名( usernames / scooby ),而不必查询或检查详细信息的子元素以找到匹配的用户名(只有在必须考虑区分大小写时才会变得更加复杂)
      • 用户名引用以小写字母存储。当我检查这个引用中的值,或者当我保存到这个引用时,我确保我只保存小写的数据。这意味着如果任何人想要检查用户名scoobY是否存在,它将失败,因为在小写字母它是现有用户史酷比相同的用户名。

      • details / [uid] / username 字段包含大写字母。这允许在用户偏好的情况下显示用户名,而不是实施小写字母或大写字母,用户可以将其名称指定为NASA Fan而不是转换成NASA Fan,同时也防止注册用户名NASA FAN(或任何其他情况下的迭代)的其他人。

      • 电子邮件正在存储在用户的详细信息中。这可能看起来很奇怪,因为您可以通过 Firebase.auth()。currentUser.email?来检索当前用户的电子邮件。这是必要的原因是因为我们需要在用户登录前引用电子邮件。
      • $ b


        1. 通过电子邮件或用户名登录





        由于我不允许用户名中的@字符,所以我可以假定包含@的登录请求是电子邮件请求。使用Firebase的 FIRAuth.auth()。signInWithEmail(电子邮件,密码,完成)方法来处理这些请求。



        对于所有其他请求,我们将假定它是一个用户名请求。 注意:强制转换为小写。

          let ref = FIRDatabase.database()。reference 
        let usernameRef = ref.child(users / usernames / \(username.lowercaseString))

        执行此检索时,应考虑是否启用了持久性,以及是否有可能会吊销用户名。如果一个用户名可以被撤消,并且你已经启用了持久化,那么你需要确保你在一个Transaction块中检索用户名的值,以确保你没有得到一个缓存的值。



        当检索成功时,您从 username [用户名] ,这是用户的uid。使用此值,您现在可以对用户的电子邮件值执行检索:

          let ref = FIRDatabase.database()。 ()
        let usernameRef = ref.child(users / details / [uid] / email)

        一旦这个请求成功,您可以使用您刚刚检索的电子邮件字符串执行标准Firebase电子邮件登录。



        完全相同的检索方法可用于检索用户名中的电子邮件,以便恢复密码。

        有几点需要注意高级功能:
        - 如果允许用户更新信息内预范或信息范讯信息范范亦读范范辛中读范亦亦信范亦中方亦内范辛中信息auth和详细信息[uid] email 字段,否则您将破坏用户名登录功能
        - 您可以显着减少处理所有不同的代码所需的代码使用成功和失败块的检索方法中的失败情况。下面是我的电子邮件方法的一个例子:

          static func getEmail(username:String,success:(email:String) - > ;失败:(错误:字符串!) - >无效){
        let usernameRef = FIRDatabase.database()。reference()。child(users / usernames / \(username.lowercaseString))信读方范亦方范范now now references now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now now nowishes references中进行参考()。child(users / details / \(userId)/ email)

        emailRef.observeSingleEventOfType(.Value,withBlock:{(snapshot)in
        if let email = snapshot.value as?String {
        success(email:email)
        } else {
        failure(error:找不到邮件用户名'\(username)'。)

        }){(错误)在
        失败(错误:电子邮件不能是fou nd。)
        }
        } else {
        失败(错误:找不到用户名'\(用户名)'。')
        }
        } ){(error)in
        failure(error:找不到用户名。)
        }
        }

        这个成功/失败块实现允许我在ViewControllers中调用的代码更加干净。 Å登录调用以下方法:

        $ p $ if fieldText.containsString(@){
        loginWithEmail(fieldText)
        } else {
        //尝试获取用户名的电子邮件。
        LoginHelper.getEmail(fieldText,success:{(email)in
        self.loginWithEmail(email)
        },失败:{error in
        HUD.flash(.Error,delay :0.5)
        })
        }


        I want to make a system which allows for username login. This process requires the following:

        1. User must register with an email/password
        2. The user can set a unique username
        3. The user can sign in with either email or username
        4. The user can recover their password via email or username
        5. The functionality must work on a persistence enabled database

        This question has been answered previously, but it disabled the functionality for the user to use password recovery. They also didn't address case-sensitivity, one person could register as "scooby" and another as "Scooby".

        解决方案

        After multiple iterations of development I've come up with the following design to address this. I will post my code snippets in Swift, but they will typically be translatable directly into Android with ease.


        1. Create a Firebase registration process for email/password.

        This is required as the backbone of the user's sign-in experience. This can be implemented completely from the stock Firebase API documentation provided here


        1. Prompt the user to enter their username

        The username entry should be completed at registration, I'd recommend an additional field in the registration flow. I also recommend checking if the user has a username whenever they log in. If they don't, then display a SetUsername interface that prompts them to set a username before progressing further into the UI. A user might not have a username for a few reasons; it could be revoked for being rude or reserved, or they might have signed up prior to the username being required at registration.

        Make sure that if you're using a persistence-enabled Firebase build that you use Firebase Transactions. The transactions are necessary, otherwise your app can make assumptions about the data in the username table, even though a username might have been set for a user only seconds earlier.

        I would also advise enforcing the username to be nearly alphanumeric (I allow for some harmless punctuation). In Swift I can achieve this with the following code:

        static var invalidCharacters:NSCharacterSet {
            let chars = NSMutableCharacterSet.alphanumericCharacterSet()
        
            // I add _ - and . to the valid characters.
            chars.addCharactersInString("_-.")
        
            return chars.invertedSet
        }
        
        if username.rangeOfCharacterFromSet(invalidCharacters) != nil {
            // The username is valid
        }
        


        1. Saving the user data

        The next important step is knowing how to save the user's data in a way that we can access it in the future. Below is a screenshot of the way I store my user data: A few things to note:

        • The usernames are stored twice, once in usernames and again in details/[uid]/username. I recommend this as it allows you to be case sensitive with usernames (see the next point) and it also allows you to know the exact database reference to check a username (usernames/scooby) rather than having to query or check through the children of details to find a username that matches (which would only become more complicated when you have to factor in case-sensitivity)
        • the usernames reference is stored in lowercase. When I check the values in this reference, or when I save to this reference, I ensure that I only save data in lowercase. This means if anyone wants to check if the username 'scoobY' exists, it will fail because in lowercase it's the same username as the existing user "Scooby".
        • The details/[uid]/username field contains capitals. This allows for the username to display in the case of preference for the user, rather than enforcing a lowercase or Capitalised word, the user can specify their name as "NASA Fan" and not be converted over to "Nasa Fan", while also preventing anyone else from registering the username "NASA FAN" (or any other case iterations)
        • The emails are being stored in the user details. This might seem peculiar because you can retrieve the current user's email via Firebase.auth().currentUser.email?. The reason this is necessary is because we need references to the emails prior to logging in as the user.

        1. Logging in with email or username

        For this to work seamlessly, you need to incorporate a few checks at login.

        Since I've disallowed the @ character in usernames, I can assume that a login request containing an @ is an email request. These requests get processed as normal, using Firebase's FIRAuth.auth().signInWithEmail(email, password, completion) method.

        For all other requests, we will assume it's a username request. Note: The cast to lowercase.

        let ref = FIRDatabase.database().reference()
        let usernameRef = ref.child("users/usernames/\(username.lowercaseString)")
        

        When you perform this retrieval, you should consider if you have persistence-enabled, and if there's a possibility that a username could be revoked. If a username could be revoked and you have persistence-enabled, you will want to ensure you retrieve the username value within a Transaction block, to make sure you don't get a cached value back.

        When this retrieval succeeds, you get the value from username[username], which is the user's uid. With this value, you can now perform a retrieval on the user's email value:

        let ref = FIRDatabase.database().reference()
        let usernameRef = ref.child("users/details/[uid]/email")
        

        Once this request succeeds, you can then perform the standard Firebase email login with the email string you just retrieved.

        The exact same retrieval methods can be used to retrieve an email from a username to allow for password recovery.

        A few points to be wary of for advanced functionality: - If you allow the user to update their email using FIRUserProfileChangeRequest, make sure you update it both on the auth AND the details[uid]email field, otherwise you will break the username login functionality - You can significantly reduce the code required to handle all the different failure cases in the retrieval methods by using success and failure blocks. Here's an example of my get email method:

        static func getEmail(username:String, success:(email:String) -> Void, failure:(error:String!) -> Void) {
            let usernameRef = FIRDatabase.database().reference().child("users/usernames/\(username.lowercaseString)")
        
            usernameRef.observeSingleEventOfType(.Value, withBlock: { (snapshot) in
                if let userId = snapshot.value as? String {
                    let emailRef = FIRDatabase.database().reference().child("users/details/\(userId)/email")
        
                    emailRef.observeSingleEventOfType(.Value, withBlock: { (snapshot) in
                        if let email = snapshot.value as? String {
                            success(email: email)
                        } else {
                            failure(error: "No email found for username '\(username)'.")
                        }
                    }) { (error) in
                        failure(error: "Email could not be found.")
                    }
                } else {
                    failure(error: "No account found with username '\(username)'.")
                }
            }) { (error) in
                failure(error: "Username could not be found.")
            }
        }
        

        This success/failure block implementation allows the code I call in my ViewControllers to be much cleaner. Å login calls the following method:

        if fieldText.containsString("@") {
            loginWithEmail(fieldText)
        } else {
            // Attempt to get email for username.
            LoginHelper.getEmail(fieldText, success: { (email) in
                self.loginWithEmail(email)
            }, failure: { error in
                HUD.flash(.Error, delay: 0.5)
            })
        }
        

        这篇关于我可以让Firebase使用用户名登录过程吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆