Проблема
Я видел этот вопрос несколько раз (также в контексте базы данных реального времени Firebase), но я не видел убедительного ответа на него. Вывод задачи довольно прост:
Как пользователи, прошедшие проверку подлинности, выбирают имя пользователя, которое еще не было принято?
Прежде всего, почему: после аутентификации пользователя у них есть уникальный идентификатор пользователя. Однако многие веб-приложения позволяют пользователю выбрать "отображаемое имя" (как пользователь хочет показать на веб-сайте), чтобы защитить персональные данные пользователей (например, настоящее имя).
Коллекция пользователей
Для структуры данных, подобной следующей, можно сохранить имя пользователя вместе с другими данными для каждого пользователя:
/users (collection)
/{uid} (document)
- name: "<the username>"
- foo: "<other data>"
Однако ничто не мешает другому пользователю (с другим {uid}
) сохранить тот же name
в своей записи. Насколько я знаю, нет "правила безопасности", которое позволяет нам проверить, был ли name
уже другим пользователем.
Примечание. Проверка на стороне клиента возможна, но небезопасно, поскольку вредоносный клиент может опустить проверку.
Обратное отображение
Популярные решения создают коллекцию с обратным отображением:
/usernames (collection)
/{name} (document)
- uid: "<the auth {uid} field>"
Учитывая это обратное отображение, можно написать правило безопасности, чтобы обеспечить, чтобы имя пользователя еще не было выполнено:
match /users/{userId} {
allow read: if true;
allow create, update: if
request.auth.uid == userId &&
request.resource.data.name is string &&
request.resource.data.name.size() >= 3 &&
get(/PATH/usernames/$(request.resource.data.name)).data.uid == userId;
}
и заставить пользователя сначала создать документ с именами пользователей:
match /usernames/{name} {
allow read: if true;
allow create: if
request.resource.data.size() == 1 &&
request.resource.data.uid is string &&
request.resource.data.uid == request.auth.uid;
}
Я считаю, что решение на полпути. Тем не менее, есть еще несколько нерешенных проблем.
Оставшиеся вопросы/вопросы
Эта реализация уже задействована, но она даже не решает проблему пользователей, которые хотят изменить свое имя пользователя (требуется удаление записей или правила обновления и т.д.).
Другая проблема заключается в том, что ничто не мешает пользователю добавлять несколько записей в коллекцию usernames
, эффективно захватывая все хорошие имена пользователей, чтобы саботировать систему.
Итак, на вопросы:
- Есть ли более простое решение для принудительного использования уникальных имен пользователей?
- Как можно запретить рассылку коллекции
usernames
? - Как проверка имени пользователя может быть нечувствительной к регистру?
Я попытался также обеспечить существование users
, с другим правилом exists()
для коллекции /usernames и затем выполнить операцию пакетной записи, однако это, похоже, не работает (ошибка "Отсутствующие или недостаточные разрешения" )).
Еще одно замечание: я видел решения с клиентскими проверками. НО ЭТИ НЕСООТВЕТСТВУЮТ. Любой вредоносный клиент может изменить код и пропустить проверки.