使用Firebase simplelogin强制使用唯一的用户名

我最近在Thinkster上使用Angular和Firebase创build了一个Web应用程序。

本教程使用Firebase simpleLogin方法允许创build包含用户名的“configuration文件”。

厂:

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; }); 

控制器:

 $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(); }); }; 

在教程的最后,有一个“下一步”部分,其中包括:

强化用户名的唯一性 – 这是一个棘手的问题,请查看Firebase的优先级并查看是否可以使用它们来通过用户名查询用户configuration文件

我已经search和search,但无法find如何做到这一点的明确解释,特别是在Firebase的setPriority()函数

我是Firebase新手,所以在这里的任何帮助将感激地收到。

有几个类似的问题 ,但我似乎无法弄清楚如何解决这个问题。

提前致以巨大的感谢。


编辑

从马林的回答我已经更新了我的控制器中的注册function,以:

 $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 } }); }; 

但是它是在var q = ref.child('profile').orderByChild('username').equalTo($scope.user.username);行中抛出'undefined不是函数'错误var q = ref.child('profile').orderByChild('username').equalTo($scope.user.username); 。 我已经注释掉了代码,并试图只是console.log(q),但仍然没有喜悦。

编辑2

上面的问题是,Thinkster教程使用Firebase 0.8,orderByChild仅在更高版本中可用。 更新和马林的答案是完美的。

这里有两件事情要做,一个客户端检查和一个服务器端规则。

在客户端,您需要检查用户名是否已经存在,以便在发送给服务器之前告诉用户input无效。 你到底在哪里实现这个,但是代码看起来像这样:

 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 } }); 

您可以在写入服务器之前使用它进行检查。 但是,如果用户是恶意的并决定使用JS控制台写入服务器呢? 为了防止这种情况,您需要服务器端安全性。

我试图提出一个示例解决scheme,但遇到了一个问题。 希望有更有知识的人会来。 我的问题如下。 假设你的数据库结构如下所示:

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

当添加一个新的configuration文件,你会想有一个规则,确保不存在具有相同的username属性的configuration文件对象。 不过,据我所知,Firebase安全性语言不支持这种数据结构。

解决方法是更改​​数据结构以使用username作为每个configuration文件的键(而不是profile1profile2 ,…)。 这样,只能有一个用户名的对象,自动。 数据库结构将是:

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

在这种情况下,这可能是一个可行的解决scheme。 但是,如果不仅是用户名,而且例如电子邮件必须是唯一的呢? 它们不能都是对象键(除非我们使用string连接…)。

还有一点需要注意的是,除了configuration文件列表外,还要提供一个单独的用户名列表和一个单独的电子邮件列表。 然后,这些可以很容易地在安全规则使用,以检查给定的用户名和电子邮件是否已经存在。 规则看起来像这样:

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

但是现在我们遇到了另一个问题。 如何确保在创build新的configuration文件时,用户名(和电子邮件)也被放置到这些新的列表中? [1]

这反过来可以通过从客户端取出configuration文件创build代码并将其放置在服务器上来解决。 然后客户端需要请求服务器创build一个新的configuration文件,服务器将确保执行所有必要的任务。

但是,似乎我们已经走了很长的一段距离来回答这个问题。 也许我忽略了一些事情,事情比看起来简单。 任何想法表示赞赏。

此外,道歉,如果这个答案更像是一个问题,而不是一个答案,我是新来的,不知道什么是适当的答案。

[1]虽然也许你可以说这不需要保证,因为恶意用户只会因为不声称自己的身份而伤害自己?

我有一个类似的问题。 但它是用密码和电子邮件注册用户。 在用户configuration文件可以保存一个用户名必须是唯一的,我已经find了解决scheme,也许这可以为您服务。

查询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); } }); }; 
Interesting Posts