Firebase зарегистрируйтесь с именем пользователя. Клиентская сторона правила безопасности или серверная часть?

#javascript #firebase #google-cloud-firestore #firebase-security

#javascript #firebase #google-облако-firestore #firebase-безопасность

Вопрос:

Я реализовал регистрацию в Firebase с именем пользователя, электронной почтой и паролем. В основном то, что я делаю, это:

1- Создайте пользователя с электронной почтой и паролем (если имя пользователя и электронная почта не используются другими пользователями)

2- Добавьте имя пользователя для пользователя

Вот так:

 firebase
  .createUserWithEmailAndPassword(email, password)
  .then((currentUser) => {
    // Get the username from the input
    const username = this.usernameInput.current.getText();

    // Create a user with this username and the current user uid in the db
    firebase.createUserWithUsername(username, currentUser.user.uid); // <----------
  })
  .catch((err) => {
    // ...  
  });
  

И моя функция createUserWithUsername в основном делает это:

 createUserWithUsername = (username, userId) => {
  /*
    Create a document in the usernames collection 
    which uid (of the document itself, not a field) is the given username.
  */

  // Pass username to lowercase
  username = username.toLowerCase();

  // Initial user's data
  const data = {
    email: this.auth.currentUser.email,
    username,
  };

  return this.db
    .collection("usernames")
    .doc(username)
    .set({ userId })
    .then(() => {
      this.db.collection("users").doc(userId).set(data);
    })
    .catch((err) => {
      console.log(err);
      throw err;
    });

  /*
    Pd: As firestore automatically removes empty documents, we have to
    assign them a field. The user's id is a good option, because it will help us to
    update usernames faster, acting like a 'Foreign Key' in a NoSql DB.
  */
};
  

Мой вопрос? Неправильно ли оставлять этот код на стороне клиента? Может ли это быть проблемой безопасности? Нужно ли мне перенести это в облачную функцию / серверную часть?

Это мое правило безопасности firestore для коллекции имен пользователей:

 match /usernames/{username} {
  function isUsernameAvailable() {
    return !exists(/databases/$(database)/documents/usernames/$(username));
  }
  
  allow read: if true;
  allow write, update: if isSignedIn() amp;amp; isUsernameAvailable();
  // TODO - Allow delete?
}
  

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

Комментарии:

1. Я думаю, вы захотите сделать это в пакетной записи или транзакции, чтобы обе записи были успешными / неудачными в тандеме. Затем вы можете использовать existsAfter() вместо exists() для проверки данных, как это будет, если запись разрешена.

2. @FrankvanPuffelen спасибо за отзыв! Почему я должен использовать транзакции для этого (я никогда их не использовал)? В моем коде я создаю документ в своей коллекции имен пользователей с идентификатором пользователя… Разве документы Firestore не создаются атомарно?!

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

4. АААА!!! Да, спасибо тебе, чувак! Теперь, если имя пользователя не может быть записано или идентификатор пользователя, вся операция завершается неудачей!