Aplicación de nombres de usuario únicos con Firebase simplelogin

Recientemente he seguido un tutorial en Thinkster para crear una aplicación web usando Angular y Firebase.

El tutorial utiliza el método Firebase simpleLogin permite crear un ‘perfil’ que incluye un nombre de usuario.

Fábrica:

app.factory('Auth', function($firebaseSimpleLogin, $firebase, FIREBASE_URL, $rootScope) { var ref = new Firebase(FIREBASE_URL); var auth = $firebaseSimpleLogin(ref); var Auth = { register: function(user) { return auth.$createUser(user.email, user.password); }, createProfile: function(user) { var profile = { username: user.username, md5_hash: user.md5_hash }; var profileRef = $firebase(ref.child('profile')); return profileRef.$set(user.uid, profile); }, login: function(user) { return auth.$login('password', user); }, logout: function() { auth.$logout(); }, resolveUser: function() { return auth.$getCurrentUser(); }, signedIn: function() { return !!Auth.user.provider; }, user: {} }; $rootScope.$on('$firebaseSimpleLogin:login', function(e, user) { angular.copy(user, Auth.user); Auth.user.profile = $firebase(ref.child('profile').child(Auth.user.uid)).$asObject(); console.log(Auth.user); }); $rootScope.$on('$firebaseSimpleLogin:logout', function() { console.log('logged out'); if (Auth.user && Auth.user.profile) { Auth.user.profile.$destroy(); } angular.copy({}, Auth.user); }); return Auth; }); 

Controlador:

 $scope.register = function() { Auth.register($scope.user).then(function(user) { return Auth.login($scope.user).then(function() { user.username = $scope.user.username; return Auth.createProfile(user); }).then(function() { $location.path('/'); }); }, function(error) { $scope.error = error.toString(); }); }; 

Al final del tutorial hay una sección de “próximos pasos” que incluye:

Imponer la exclusividad del nombre de usuario: este es complicado, revisa las prioridades de Firebase y mira si puedes usarlas para consultar perfiles de usuario por nombre de usuario

He buscado y buscado, pero no puedo encontrar una explicación clara de cómo hacerlo, particularmente en términos de la función setPriority () de Firebase

Soy bastante novato de Firebase por lo que cualquier ayuda aquí sería recibida con gratitud.

Hay algunas preguntas similares , pero parece que no puedo entender cómo solucionar esto.

Enormes gracias de antemano.


EDITAR

De la respuesta de Marein, he actualizado la función de registro en mi controlador para:

 $scope.register = function() { var ref = new Firebase(FIREBASE_URL); var q = ref.child('profile').orderByChild('username').equalTo($scope.user.username); q.once('value', function(snapshot) { if (snapshot.val() === null) { Auth.register($scope.user).then(function(user) { return Auth.login($scope.user).then(function() { user.username = $scope.user.username; return Auth.createProfile(user); }).then(function() { $location.path('/'); }); }, function(error) { $scope.error = error.toString(); }); } else { // username already exists, ask user for a different name } }); }; 

Pero arroja un error ‘no definido no es una función’ en la línea var q = ref.child('profile').orderByChild('username').equalTo($scope.user.username); . He comentado el código después e intenté simplemente console.log (q) pero todavía no me gustó.

EDIT 2

El problema con lo anterior es que el tutorial de Thinkster usa Firebase 0.8 y orderByChild está disponible solo en versiones posteriores. Actualizado y la respuesta de Marein es perfecta.

Aquí hay dos cosas que hacer, una verificación del lado del cliente y una regla del lado del servidor.

En el lado del cliente, desea verificar si el nombre de usuario ya existe, para que pueda decirle al usuario que su entrada no es válida, antes de enviarlo al servidor. Donde exactamente lo implementas esto, pero el código se vería así:

 var ref = new Firebase('https://YourFirebase.firebaseio.com'); var q = ref.child('profiles').orderByChild('username').equalTo(newUsername); q.once('value', function(snapshot) { if (snapshot.val() === null) { // username does not yet exist, go ahead and add new user } else { // username already exists, ask user for a different name } }); 

Puede usar esto para verificar antes de escribir en el servidor. Sin embargo, ¿qué pasa si un usuario es malicioso y decide usar la consola JS para escribir en el servidor de todos modos? Para evitar esto, necesita seguridad en el servidor.

Traté de encontrar una solución de ejemplo pero tuve un problema. Con suerte, alguien más conocedor vendrá. Mi problema es el siguiente. Digamos que la estructura de su base de datos se ve así:

 { "profiles" : { "profile1" : { "username" : "Nick", "md5_hash" : "..." }, "profile2" : { "username" : "Marein", "md5_hash" : "..." } } } 

Al agregar un nuevo perfil, le conviene tener una regla que garantice que no exista ningún objeto de perfil con la misma propiedad de username . Sin embargo, hasta donde yo sé, el lenguaje de seguridad de Firebase no es compatible con esta estructura de datos.

Una solución sería cambiar la estructura de datos para usar el username como clave para cada perfil (en lugar de profile1 , profile1 , …). De esa forma solo puede haber un objeto con ese nombre de usuario, automáticamente. La estructura de la base de datos sería:

 { "profiles" : { "Nick" : { "md5_hash" : "..." }, "Marein" : { "md5_hash" : "..." } } } 

Esta podría ser una solución viable en este caso. Sin embargo, ¿qué sucede si no solo el nombre de usuario, pero también el correo electrónico tiene que ser único? No pueden ser ambas la clave del objeto (a menos que usemos la concatenación de cadenas …).

Otra cosa que viene a la mente es, además de la lista de perfiles, mantener una lista separada de nombres de usuario y una lista separada de correos electrónicos también. Luego, se pueden usar fácilmente en las reglas de seguridad para verificar si el nombre de usuario y el correo electrónico ya existen. Las reglas se verían así:

 { "rules" : { ".write" : true, ".read" : true, "profiles" : { "$profile" : { "username" : { ".validate" : "!root.child('usernames').child(newData.val()).exists()" } } }, "usernames" : { "$username" : { ".validate" : "newData.isString()" } } } } 

Sin embargo, ahora nos encontramos con otro problema; ¿cómo asegurar que cuando se crea un nuevo perfil, el nombre de usuario (y el correo electrónico) también se colocan en estas nuevas listas? [1]

Esto a su vez puede resolverse sacando el código de creación de perfil del cliente y colocándolo en un servidor. El cliente necesitaría pedirle al servidor que creara un nuevo perfil, y el servidor se aseguraría de que se ejecutaran todas las tareas necesarias.

Sin embargo, parece que hemos avanzado mucho para responder esta pregunta. Quizás he pasado por alto algo y las cosas son más simples de lo que parecen. Cualquier pensamiento es apreciado

Además, me disculpo si esta respuesta es más como una pregunta que una respuesta, soy nuevo en SO y aún no estoy seguro de qué es lo apropiado como respuesta.

[1] Aunque tal vez podría argumentar que no es necesario garantizar esto, ya que un usuario malintencionado solo se dañaría a sí mismo al no reclamar su identidad única.

Tuve un problema similar. Pero fue después de registrar al usuario con contraseña y correo electrónico. En el perfil del usuario podría guardar un nombre de usuario que debe ser único y he encontrado una solución, tal vez esto pueda servirle.

Consulta de nombre de usuario único en Firebase

  var ref = new Firebase(FIREBASE_URL + '/users'); ref.orderByChild("username").equalTo(profile.username).on("child_added", function(snapshot) { if (currentUser != snapshot.key()) { scope.used = true; } }); ref.orderByChild("username").equalTo(profile.username).once("value", function(snap) { //console.log("initial data loaded!", Object.keys(snap.val()).length === count); if (scope.used) { console.log('username already exists'); scope.used = false; }else{ console.log('username doesnt exists, update it'); userRef.child('username').set(profile.username); } }); }; 
    Intereting Posts