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

12 浏览
0 Comments

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

最近我在Thinkster上参考了一个教程,学习使用Angular和Firebase来创建一个Web应用程序。

教程使用了Firebase的simpleLogin方法,允许创建一个包含用户名的'profile'。

工厂:

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的优先级,看看是否可以使用它们来通过用户名查询用户配置文件

我已经搜索了很多,但找不到如何做到这一点的明确解释,特别是在Firebase的setPriority()函数方面。

我对Firebase还是个新手,所以在这方面任何帮助都将不胜感激。


编辑

根据Marein的答案,我已经更新了控制器中的register函数为:

$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 {
            // 用户名已存在,请用户输入一个不同的名称
        }
    });
};

但是,在var q = ref.child('profile').orderByChild('username').equalTo($scope.user.username);这一行出现了'undefined is not a function'的错误。我已经将后面的代码注释掉并尝试了console.log(q),但仍然没有成功。

编辑 2

以上问题的原因是Thinkster教程使用的是Firebase 0.8版本,而orderByChild只在较新的版本中可用。更新了版本后,Marein的答案是完美的。

0
0 Comments

在使用Firebase simplelogin进行用户注册后,我遇到了一个类似的问题。在用户配置文件中,我需要保存一个唯一的用户名,但是我找到了一个解决方法,也许这对你有用。

问题出现的原因是,我需要确保用户输入的用户名在数据库中是唯一的。为了解决这个问题,我使用了Firebase的orderByChild和equalTo方法来查询数据库中是否已存在相同的用户名。如果存在相同的用户名,我会将一个布尔值变量used设置为true,表示用户名已被使用。然后,我使用once方法来获取数据库中的数据,并根据used变量的值来判断是否需要更新用户名。

下面是代码示例:

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

通过以上代码,我成功解决了在Firebase simplelogin中强制实现唯一用户名的问题。希望这个解决方法对你也有帮助。

0
0 Comments

Firebase simplelogin是一个用于管理用户认证和授权的Firebase插件。在使用Firebase simplelogin时,你可能会遇到一个问题,即如何强制用户名的唯一性。问题的原因以及解决方法。

问题的原因是,当用户在客户端输入用户名时,需要在发送到服务器之前检查该用户名是否已存在。在客户端,可以使用以下代码来实现这个检查:

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) {
    // 用户名不存在,可以添加新用户
  } else {
    // 用户名已存在,请用户选择不同的名称
  }
});

然而,如果用户恶意使用JS控制台来写入服务器,上述的客户端检查就无效了。为了防止这种情况发生,需要在服务器端实施安全措施。

然而,当尝试提供一个解决方案时,遇到了一个问题。假设数据库的结构如下:

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

希望在添加新的profile时,能够确保没有具有相同username属性的profile对象存在。然而,据所知,Firebase安全语言不支持这种数据结构的规则。

解决方法是改变数据结构,使用username作为每个profile的键(而不是profile1、profile2等)。这样,就只能有一个具有该用户名的对象存在。数据库结构将变为:

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

这在这种情况下可能是一个可行的解决方案。然而,如果不仅username,还有email也需要唯一,该怎么办呢?除非我们使用字符串拼接,否则它们不能都成为对象的键。

另一个想法是,除了profiles列表外,还保持一个单独的usernames列表和一个单独的emails列表。然后可以在安全规则中轻松地使用它们来检查给定的username和email是否已存在。安全规则将如下所示:

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

然而,现在我们又遇到了另一个问题:如何确保在创建新的profile时,用户名(和email)也被放入这些新的列表中?

这个问题可以通过将profile创建的代码从客户端移到服务器上来解决。客户端将需要向服务器请求创建新的profile,而服务器将确保执行所有必要的任务。

然而,我们似乎走得太远来回答这个问题了。也许我忽视了一些简单的解决方法。欢迎任何想法。

总结起来,解决强制用户名唯一性的问题,可以在客户端进行检查并在服务器端实施安全规则。改变数据结构或者使用单独的列表来记录用户名和email的唯一性也是解决方案之一。将profile创建的代码放在服务器上也可以解决添加新的用户名和email到列表的问题。

0