Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you prevent duplicate user properties in Firebase?

I'm Using FirebaseSimpleLogin to create users and handle authentication.

When I try and create a new user with simple login via the $createUser() method, firebase won't create the user if the email address has already been used. However, I am also using $set() to save my created users to my firebase after I create them and I am using user.uid as the key. When trying to write to the database, firebase will save the record even if the username is not unique since only email and password are required for simple login. So how can I validate a username to be unique when it is not being used as the key to the user object?

I'm creating new users like this:

$scope.createUser = function() {   $scope.auth.$createUser('[email protected]', 'password').then(function(user, err) {     if (!err) {       ref.child('users/' + user.uid).set({         email: user.email,         username: user.username       });       console.log("success!");     }else{       console.log(err.message);     }   }); } 

And my user object looks like this:

{   "users" : {     "simplelogin:28" : {       "email" : "[email protected]",       "username" : "jtrinker"     },     "simplelogin:30" : {       "email" : "[email protected]",       "username" : "jtrinker"     }   } }  } 

I need to use the uid as the key for each user, but I still need the username to be unique.

How can I can I prevent firebase from saving records if properties within one object are not unique to properties inside a different object?

like image 963
reknirt Avatar asked Aug 13 '14 19:08

reknirt


People also ask

How do I avoid duplicates in firebase?

The best way to prevent duplicate nodes in firebase realtime database or duplicate documents in firebase firestore database is to keep a check in the app itself to verify that the record to be inserted doesn't already exist in the database by querying for data using key field in where clause.

Are users in firebase unique?

Firebase users have a fixed set of basic properties—a unique ID, a primary email address, a name and a photo URL—stored in the project's user database, that can be updated by the user (iOS, Android, web).

Can firebase handle 10 million users?

The limit you're referring to is the limit for the number of concurrently connected users to Firebase Realtime Database on the free Spark plan. Once you upgrade to a payment plan, your project will allow 200,000 simultaneously connected users.


1 Answers

First of all, if users already have a username, it's unique, and this is not going to go away, I'd recommend that you give up on using simple login uids. This is going to create nothing but issues trying to flip back and forth between the two, as you've already discovered here. Investigate creating your own tokens with a tool like firebase-passport-login and then store the records by username.

But since that wasn't your question, let's resolve that while we're here, since you may want to go ahead and enter the thorny briar of dual identities through which I have passed many times.

To make the username unique, store an index of usernames.

/users/$userid/username/$username /usernames/$username/$userid 

To ensure they are unique, add a security rule as follows on the user id in usernames/ path, which ensures only one user can be assigned per username and that the value is the user's id:

".write": "newData.val() === auth.uid && !data.exists()" 

Now enforce that they match by adding the following to the username in the users/ record:

"users": {    "$userid": {       "username": {          ".validate": "root.child('usernames/'+newData.val()).val() === $userid"       }    } } 

This will ensure the ids are unique. Be careful with read privileges. You may want to avoid those entirely since you don't want anyone looking up private emails or usernames. Something like I demonstrated in support for saving these would be ideal.

The idea here is that you try to assign the username and email, if they fail, then they already exist and belong to another user. Otherwise, you insert them into the user record and now have users indexed by uid and email.

To comply with SO protocol, here's the code from that gist, which is better read via the link:

var fb = new Firebase(URL);  function escapeEmail(email) {    return email.replace('.', ','); }  function claimEmail(userId, email, next) {    fb.child('email_lookup').child(escapeEmail(email)).set(userId, function(err) {       if( err ) { throw new Error('email already taken'); }       next();    }); }  function claimUsername(userId, username, next) {    fb.child('username_lookup').child(username).set(userId, function(err) {       if( err ) { throw new Error('username already taken'); }       next();    });    }  function createUser(userId, data) {    claimEmail(userId, data.email, claimUsername.bind(null, userId, data.username, function() {       fb.child('users').child(userId).set(data);    );    } 

And the rules:

{   "rules": {      "users": {         "$user": {            "username": {                ".validate": "root.child('username_lookup/'+newData.val()).val() === auth.uid"            },            "email": {                ".validate": "root.child('email_lookup').child(newData.val().replace('.', ',')).val() === auth.uid"            }         }      },       "email_lookup": {         "$email": {            // not readable, cannot get a list of emails!            // can only write if this email is not already in the db            ".write": "!data.exists()",            // can only write my own uid into this index            ".validate": "newData.val() === auth.uid"         }      },      "username_lookup": {         "$username": {            // not readable, cannot get a list of usernames!            // can only write if this username is not already in the db            ".write": "!data.exists()",             // can only write my own uid into this index            ".validate": "newData.val() === auth.uid"         }      },   } } 
like image 186
Kato Avatar answered Oct 05 '22 17:10

Kato