Разрешить пользователю обновлять свой собственный документ (но не роли), используя правила безопасности Firestore - PullRequest
0 голосов
/ 20 апреля 2019

Мое приложение хранит роль пользователя (подписчик, редактор или администратор) в виде карты «ролей» в своем пользовательском документе в коллекции пользователей Firestore. Ролевая карта выглядит так:

// Roles map for a subscriber
{
subscriber: true 
}

// Roles map for a editor
{
editor: true 
}

// Roles map for administrator
{
administrator: true 
}

Я также могу по мере необходимости помещать несколько (или совершенно новые) ролевые поля в ролевую карту пользовательского документа.

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

match /users/{userUid} {
  allow update: if 
  (
    isOwner(userUid) &&
    (
      (request.resource.data.roles.administrator == resource.data.roles.administrator) &&
      (request.resource.data.roles.editor == resource.data.roles.editor) &&
      (request.resource.data.roles.subscriber == resource.data.roles.subscriber)
    )
  );
}

Первое isOwner(user) условие выглядит следующим образом:

function isOwner(uid) {
    return (isSignedIn() && (request.auth.uid == uid));
}

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

Я подозреваю, что моя проблема может заключаться в том, что в тех случаях, когда одно из полей ролей (например, подписчик) не существует до или после записи, оно не проходит проверку на равенство. Поэтому я также попытался добавить условие, разрешающее, если существующий объект не имеет этого поля, но он все еще не работает:

match /users/{userUid} {
  allow update: if 
  (
    isOwner(userUid) &&
    (
      (!request.resource.data.roles.administrator || request.resource.data.roles.administrator == resource.data.roles.administrator) &&
      (!request.resource.data.roles.editor || request.resource.data.roles.editor == resource.data.roles.editor) &&
      (!request.resource.data.roles.subscriber || request.resource.data.roles.subscriber == resource.data.roles.subscriber)
    )
  );
}

Заранее спасибо за любую помощь.


ОБНОВЛЕНИЕ 1

I нашел более простое решение с использованием writeFields, которое работает, но writeFields устарело, так что это не долгосрочное решение:

allow update: if isOwner(userUid) && !('roles' in request.writeFields)

Опять-таки, writeFields устарел, поэтому его не следует использовать.


ОБНОВЛЕНИЕ 2

Это решение сработало для меня, заменив роль ролями, соответствующими моему случаю: https://stackoverflow.com/a/48214390/4407512

1 Ответ

0 голосов
/ 24 апреля 2019

request.resource.data - объект типа карты. Как вы сказали, вы можете убедиться, что свойства всегда существуют, или вы можете проверить, существует ли свойство на карте, прежде чем использовать их. Операция in над объектами Map позволит вам узнать, существует ли свойство. См. Документацию на Карта для получения более подробной информации.

"administrator" in request.resource.data   // true if administrator property exists
...