2015-04-30 3 views
8

Недавно я начал обучение по адресу Thinkster для создания веб-приложения с использованием Angular and Firebase.Выполнение уникальных имен пользователей с помощью Firebase simplelogin

В учебном пособии метод SimpleLogin Firebase позволяет создать «профиль», который включает имя пользователя.

Фабрика:

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 приоритеты и посмотреть, если вы можете использовать их для запроса профилей пользователей по имени пользователя

Я искал и искал, но не может найти ясное объяснение того, как сделать это, в частности, с точки зрения setPriority() функция Firebase

Я довольно новичок Firebase, поэтому любая помощь здесь была бы с благодарностью получена.

Есть несколько similar questions, но я не могу понять, как это разобраться.

Огромное спасибо заранее.


EDIT

От ответа Marein, я обновил функцию регистров в моем контроллере:

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

Но это бросает «неопределенный не является функция» ошибка в line var q = ref.child('profile').orderByChild('username').equalTo($scope.user.username);. Я прокомментировал код после и попробовал просто console.log (q), но все равно не радость.

РЕДАКТИРОВАТЬ 2

Проблема с указанными выше в том, что учебник Thinkster использует Firebase 0,8 и orderByChild доступен только в более поздних версиях. Обновленный ответ Марейн - это прекрасно.

+1

Я не понимаю, как учебник означает использовать приоритеты с этим, возможно, они имели в виду [запросы] (https://www.firebase.com/docs/web/api/query /). Они могут использоваться для проверки на стороне клиента, существует ли пользователь с определенным именем пользователя. Кроме того, вы можете захотеть ознакомиться с правилами безопасности на стороне сервера, чтобы предотвратить запись уже существующих имен пользователей. – Marein

+1

Хорошая точка Marein, я думаю, что часть учебника мыслителя может быть слева от того, когда перед Firebase поддерживается 'orderByChild'.Тогда все, что у вас было, было «setPriority», так что это был бы единственный механизм запросов. В настоящее время я бы просто просто сохранил адрес электронной почты пользователей в своем '/ profile/' узле, а затем 'ref.child ('profile'). OrderByChild ('email'). EqualTo (emailThatIsTryingToRegister) .once ('value'. ..' –

+0

Спасибо вам @FrankvanPuffelen - Я думаю, что понимаю это концептуально, но не могли бы вы дать мне некоторое представление о том, где и как это будет вписываться в мой существующий код? Кроме того, я полагаю, что в моем конкретном использовании Я бы использовал 'orderByChild ('username')'? –

ответ

16

Здесь есть две вещи, проверка на стороне клиента и правило на стороне сервера.

На стороне клиента вы хотите проверить, существует ли имя пользователя, чтобы вы могли сообщить пользователю, что их ввод недействителен, прежде чем отправлять его на сервер. Где именно вы реализуете это до вас, но код будет выглядеть примерно так:

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 в качестве ключа для каждого профиля (вместо profile1, profile2, ...). Таким образом, может быть только один объект с этим именем пользователя, автоматически. Структура базы данных будет:

{ 
    "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" : { 
     ".validata" : "newData.isString()" 
     } 
    } 
    } 
} 

Однако теперь мы сталкиваемся с другой проблемой; как обеспечить, чтобы при создании нового профиля имя пользователя (и электронная почта) также помещалось в эти новые списки? [1]

Это, в свою очередь, может быть решено путем принятия кода создания профиля из клиента и размещения его на сервере. Затем клиенту необходимо попросить сервер создать новый профиль, и сервер обеспечит выполнение всех необходимых задач.

Однако, похоже, мы прошли очень далеко вниз, чтобы ответить на этот вопрос. Возможно, я кое-что забыл, и все проще, чем кажется. Любые мысли оцениваются.

Кроме того, извините, если этот ответ больше похож на вопрос, чем на ответ, я новичок в SO и еще не уверен, что подходит в качестве ответа.

[1] Хотя, возможно, вы можете утверждать, что этого не нужно, поскольку злоумышленник может нанести вред себе, не претендуя на свою уникальную идентификацию?

+0

Удивительный ответ Marein! –

+1

Спасибо, Фрэнк! Хотя я чувствую, что это немного открыто. Может быть, вам что-нибудь добавить? – Marein

+0

Спасибо @Marein! начальное решение будет работать, так как мои правила Firebase позволяют только записывать данные «профилей», если пользователь авторизован - Simplebin Firebase обрабатывает уникальность электронной почты отдельно fr о моей базе данных. В этом случае профиль записывается после создания пользователя. Я проверю код сегодня вечером, когда я доберусь до компьютера и отчитаюсь! Большое спасибо за такой тщательный ответ –

-1

У меня была аналогичная проблема. Но это было после регистрации пользователя с паролем и электронной почтой. В профиле пользователя можно сохранить имя пользователя, которое должно быть уникальным, и я нашел решение, возможно, это может вам помочь.

Query for username unique in 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); 
      } 
     }); 
    }; 
Смежные вопросы