当前位置: 首页 > 面试题库 >

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

章海
2023-03-14
问题内容

我最近遵循了有关Thinkster的教程,以使用Angular和Firebase创建Web应用程序

教程使用Firebase simpleLogin方法允许创建包含用户名的“配置文件”。

厂:

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 {
            // username already exists, ask user for a different name
        }
    });
};

但这会在行中引发“未定义不是函数”错误var q =ref.child('profile').orderByChild('username').equalTo($scope.user.username);。我已经注释掉了代码,然后尝试只使用console.log(q),但仍然没有任何乐趣。

编辑2

上面的问题是,Thinkster教程使用Firebase0.8,而orderByChild仅在更高版本中可用。更新,Marein的答案非常完美。


问题答案:

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

在客户端,您需要检查用户名是否已经存在,以便在将用户名输入到服务器之前,可以告诉用户其输入无效。具体在哪里实现,但代码看起来像这样:

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

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

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

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

一个解决办法是改变数据结构使用username的每个配置文件键(而不是profile1profile2......)。这样,就只能自动有一个带有该用户名的对象。数据库结构为:

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

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

除了配置文件列表之外,还要想到的另一件事是,还要保留一个单独的用户名列表和一个单独的电子邮件列表。然后可以轻松地将它们用于安全规则中,以检查给定的用户名和电子邮件是否已经存在。规则如下所示:

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

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

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

但是,似乎我们已经很不容易回答这个问题了。也许我忽略了某些事情,而且事情比看起来简单。任何想法表示赞赏。

另外,如果这个答案更像是一个问题而不是答案,我深表歉意。我是SO的新手,不确定是否适合作为答案。

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



 类似资料:
  • 问题内容: 使用django在服务器上使用唯一文件名重命名照片的最佳方法是什么?我想确保每个名称仅使用一次。是否有可能使用GUID的pinax应用程序可以做到这一点? 问题答案: ```

  • 问题内容: 我定义了一个MySQL表: 我在这里阅读到MySQL不支持带条件的。对于每个 customerId, 我们只有一个 primaryImage = 1 。 那么我还能采取什么措施来强制执行此约束? 问题答案: 完美支持独特的约束。 但是,它不支持部分约束/索引,因此您需要使用而不是标记非主图像。 您可以将任意数量的值插入到每个客户中,但只能插入一个非空值。

  • Parse将在年底关闭,所以我决定开始使用Firebase。我需要用3个字段实现注册过程:电子邮件、用户名、密码(电子邮件 由于Firebase没有提供像Parse这样管理用户名的简单方法,我决定只使用电子邮件/密码注册并保存一些附加数据,例如用户名。这是我的用户数据结构: 但是,我想做的是使用户名唯一,并在创建帐户之前进行检查。以下是我的规则: 非常感谢您的帮助

  • 我们正在制作一个Kafka队列,消息从源系统发布到该队列中。现在多个使用者可以连接到这个队列来读取消息。

  • 这是我的限制: 该查询证明约束实际上不起作用: 下面是输出: 为什么唯一性没有被强制执行?

  • 一点背景:我是一个AEM项目的FE开发人员。该项目是一个SPA AEM作为云服务。我从命令行运行作者实例。 我的电脑规格是: CPU: Intel(R)Core(TM)i5-7400 CPU@3.00GHz 3.00 GHz RAM: 24.0 GB SSD: 476 GB 操作系统:Windows 10 Pro 对于我们正在使用的AEM项目 Javasdk 11 Maven 3.6.3 我已经设