使用 Firebase simplelogin 强制使用唯一用户名 [英] Enforcing unique usernames with Firebase simplelogin

查看:23
本文介绍了使用 Firebase simplelogin 强制使用唯一用户名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近学习了关于 Thinkster 的教程,用于创建一个使用 Angular 和 Firebase 的网络应用.

I have recently followed a tutorial over on Thinkster for creating a web app using Angular and Firebase.

本教程使用 Firebase simpleLogin 方法允许创建包含用户名的配置文件".

The tutorial uses the Firebase simpleLogin method allows a 'profile' to be created that includes a username.

工厂:

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

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

At the very end of the tutorial there is a 'next steps' section which includes:

强制用户名唯一性——这个很棘手,查看 Firebase 优先级,看看是否可以使用它们按用户名查询用户配置文件

Enforce username uniqueness-- this one is tricky, check out Firebase priorities and see if you can use them to query user profiles by username

我进行了搜索和搜索,但找不到有关如何执行此操作的明确说明,尤其是在 setPriority() Firebase 函数

I have searched and searched but can't find a clear explanation of how to do this, particularly in terms of the setPriority() function of Firebase

我是 Firebase 的新手,因此非常感谢这里的任何帮助.

I'm quite the Firebase newbie so any help here would be gratefully recieved.

有几个类似的问题,但我似乎不知道如何解决这个问题.

There are a few similar questions, but I can't seem to get my head around how to sort this out.

非常感谢.

编辑

根据 Marein 的回答,我已将控制器中的注册功能更新为:

From Marein's answer I have updated the register function in my controller to:

$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) 行中抛出了未定义不是函数"错误;.之后我注释掉了代码并尝试了 console.log(q) 但仍然没有乐趣.

But it is throwing an 'undefined is not a function' error in the line var q = ref.child('profile').orderByChild('username').equalTo($scope.user.username);. I have commented out the code after and tried just console.log(q) but still no joy.

编辑 2

上述问题是 Thinkster 教程使用 Firebase 0.8,而 orderByChild 仅在更高版本中可用.更新,Marein 的回答是完美的.

The issue with the above was that the Thinkster tutorial uses Firebase 0.8 and orderByChild is available only in later versions. Updated and Marein's answer is perfect.

推荐答案

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

There are two things to do here, a client-side check and a server-side rule.

在客户端,您要检查用户名是否已存在,以便在将其发送到服务器之前告诉用户他们的输入无效.具体在哪里实现取决于你,但代码看起来像这样:

At the client side, you want to check whether the username already exists, so that you can tell the user that their input is invalid, before sending it to the server. Where exactly you implement this up to you, but the code would look something like this:

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 控制台写入服务器怎么办?为了防止这种情况,您需要服务器端安全.

You can use this to check before writing to the server. However, what if a user is malicious and decides to use the JS console to write to the server anyway? To prevent this you need server-side security.

我试图想出一个示例解决方案,但遇到了问题.希望有更懂行的人出现.我的问题如下.假设您的数据库结构如下所示:

I tried to come up with an example solution but I ran into a problem. Hopefully someone more knowledgeable will come along. My problem is as follows. Let's say your database structure looks like this:

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

在添加新配置文件时,您希望有一个规则确保不存在具有相同 username 属性的配置文件对象.但是,据我所知,Firebase 安全语言不支持这种数据结构.

When adding a new profile, you'd want to have a rule ensuring that no profile object with the same username property exists. However, as far as I know the Firebase security language does not support this, with this data structure.

解决方案是更改数据结构以使用 username 作为每个配置文件的键(而不是 profile1profile2、...)这样一来,自动只能有一个具有该用户名的对象.数据库结构为:

A solution would be to change the datastructure to use username as the key for each profile (instead of profile1, profile2, ...). That way there can only ever be one object with that username, automatically. Database structure would be:

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

在这种情况下,这可能是一个可行的解决方案.但是,如果不仅用户名而且例如电子邮件必须是唯一的怎么办?它们不能都是对象键(除非我们使用字符串连接...).

This might be a viable solution in this case. However, what if not only the username, but for example also the email has to be unique? They can't both be the object key (unless we use string concatenation...).

我想到的另一件事是,除了个人资料列表之外,还要保留一个单独的用户名列表和一个单独的电子邮件列表.然后可以在安全规则中轻松使用它们来检查给定的用户名和电子邮件是否已经存在.规则看起来像这样:

One more thing that comes to mind is to, in addition to the list of profiles, keep a separate list of usernames and a separate list of emails as well. Then those can be used easily in security rules to check whether the given username and email already exist. The rules would look something like this:

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

然而现在我们遇到了另一个问题;如何确保在创建新配置文件时,用户名(和电子邮件)也被放入这些新列表中?[1]

However now we run into another problem; how to ensure that when a new profile is created, the username (and email) are also placed into these new lists? [1]

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

This in turn can be solved by taking the profile creation code out of the client and placing it on a server instead. The client would then need to ask the server to create a new profile, and the server would ensure that all the necessary tasks are executed.

然而,我们似乎在回答这个问题上已经走得很远了.也许我忽略了一些事情,事情比看起来更简单.任何想法表示赞赏.

However, it seems we have gone very far down a hole to answer this question. Perhaps I have overlooked something and things are simpler than they seem. Any thoughts are appreciated.

另外,如果这个答案更像是一个问题而不是答案,我很抱歉,我是新来的,不确定什么是合适的答案.

Also, apologies if this answer is more like a question than an answer, I'm new to SO and not sure yet what is appropriate as an answer.

[1] 尽管您可能会争辩说这不需要确保,因为恶意用户只会通过不声明其唯一身份来伤害自己?

这篇关于使用 Firebase simplelogin 强制使用唯一用户名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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