Система ролей доступа к безопасности Firestore - PullRequest
0 голосов
/ 07 августа 2020

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

  • Администратор: может читать и писать что угодно в организации
  • Менеджер: может читать что угодно в организации , но не писать, если это не их собственный документ
  • Сотрудник: может читать и обновлять свои собственные данные

Я нашел документацию Google по этому топу c (https://firebase.google.com/docs/firestore/solutions/role-based-access), но я не хочу, чтобы каждый менеджер или администратор у каждого пользователя и учреждения, потому что это слишком много дублированных данных. Кроме того, роли должны применяться к любой части организации, они не должны отличаться для каждой подколлекции.

Моя база данных:

organisations{
    organisation1{
    <data about organisation>
       establishments{
           establishment1{
              <data about establishment>
           }
           establishment2{
               <data about establishment>
           }
       }
       people{
           user1{
               <data about user>
               userId: <UID from authentication>
               accountType: <Administrator, Manager or Employee>
           }
           user2{
               <data about user>
               userId: <UID from authentication>
               accountType: <Administrator, Manager or Employee>
           }
       }
    }
    organisation2{
    <data about organisation>
       establishments{
           establishment1{
              <data about establishment>
           }
           establishment2{
               <data about establishment>
           }
       }
       people{
           user1{
               <data about user>
               userId: <UID from authentication>
               accountType: <Administrator, Manager or Employee>
               documents{
                   some documents
               }
           }
           user2{
               <data about user>
               userId: <UID from authentication>
               accountType: <Administrator, Manager or Employee>
           }
       }
   }
}

Я знаю, что это довольно много, но это может помочь кто-то понимает мою проблему немного лучше. Администратор (кто-то с типом accountType Администратор) должен иметь возможность читать и писать в любом месте организации (organization1 или organization2). Менеджер должен иметь возможность только читать все, но не писать, если это не его собственные данные (так что они могут читать что угодно, но имеют те же права на запись, что и сотрудник, они могут только писать документы и где угодно в подколлекциях тех документов, у которых есть свои request.auth.uid в качестве поля userId, например user1 в organization2, должен иметь возможность записывать документ user1, а также каждый документ в любой подколлекции)

В настоящее время у меня есть следующее, и я думаю, что мне нужно чтобы получить что-то вроде этого:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
  //Access levels:
  //Medewerker: Can only see their own user document and all subcollections
  //Beheerder: Can see any document within the organisation
  //Administrator: Can see and do everything

    function getAccountType(orgId, userId) {
      return get(/databases/$(database)/documents/organisations/$(orgId)/people/$(userId)).data.accountType;
    }
    function isAdmin(orgID){
      return getAccountType(orgID, request.auth.uid) == "Administrator";
    }
    function isBeheerder(orgID){
      return getAccountType(orgID, request.auth.uid) == "Beheerder";
    }
    function isOwnData(userId){
      return request.auth.uid == userId;
    }
    function authenticated(){
      return request.auth != null;
    }
    match /organisations/{orgID} {
      //Administrator rule goes here
      allow write: if authenticated() && (isAdmin(resource.data.organisationId));
      
      //Beheerder rule goes here
      allow read: if authenticated() && (isAdmin(resource.data.organisationId) || isBeheerder(resource.data.organisationId));

      match /people/{userID} {
        //Medewerker rule goes here
        allow read: if authenticated() && (isAdmin(resource.data.organisationId) || isBeheerder(resource.data.organisationId) || isOwnData(resource.data.userId));
        allow update: if authenticated() && (isAdmin(resource.data.organisationId) || isOwnData(resource.data.userId));
        allow create, delete: if authenticated() && (isAdmin(resource.data.organisationId));
      }
    }
  }
}

Код, который у меня есть сейчас, не выдает ошибок, но он ведет себя не так, как я ожидал. Когда я вхожу в систему с учетной записью администратора, я сначала вижу только свою собственную запись пользователя. Если я вхожу в систему с учетной записью Beheerder или Medewerker, я вообще не получаю никаких записей, даже своих собственных. Кроме того, если я снова изменю свою учетную запись на «Администратор», я не получу обратно свою собственную запись. Есть ли способ исправить это / что не так с моим кодом? Кроме того, нужен ли мне идентификатор организации в каждом документе или есть обходной путь? В моем текущем коде это было. Спасибо за помощь!

1 Ответ

2 голосов
/ 07 августа 2020

Поскольку этот вопрос довольно большой, вот две вещи:

1. Пример проекта с 3-мя уровнями доступа (создан для этого вопроса)

Полный образец с открытым исходным кодом здесь , не стесняйтесь клонировать / разветвлять и вносить свой вклад при необходимости. * Модель Firestore

  • организации (коллекция)
    • организация1 (do c)
      • Название организации (поле)
      • createdAt (поле)
      • заведения (коллекция)
        • организация 1 (do c)
        • учреждение 2 (do c)
      • людей (сбор)
        • userId (do c)
          • uid : идентификатор пользователя (поле)
          • accountType : "admin" || "модератор" || "peon" (поле)
          • документы (коллекция)
            • docId (do c)

Сведения об уровне доступа:

Админ

  • прочтите: вся организация, в которой он состоит (включая учреждения, документы людей, организацию)
  • напишите: вся организация, в которой он состоит (включая учреждения, документы людей, организацию)

Модератор

  • прочтите: вся организация, в которой он состоит (включая учреждения, документы людей, организацию)
  • напишите: только его собственные документы (organizations/orgId/peoples/userId/documents/*)

Пеон

  • читать: только его собственные документы (organizations/orgId/peoples/userId/documents/*), а не организацию или учреждение
  • напишите: только его собственные документы (organizations/orgId/peoples/userId/documents/*)

firestore.rules (объяснение)

function getAccountType(orgId, userId) {
    return get(/databases/$(database)/documents/organizations/$(orgId)/peoples/$(userId)).data.accountType;
}

Этот запрос роли данный пользователь в параметрах для ги Ven организация по параметру. Наличие этого параметра в параметре позволяет легко использовать его с request.data или с id из правила сопоставления.

function isAdmin(orgID){
    return getAccountType(orgID, request.auth.uid) == "admin";
}

Проверить, есть ли у текущего вошедшего в систему пользователя request.auth.uid "admin" роли для данной организации в параметре.

match /organizations/{orgID} {
    allow read: if authenticated() && (isAdmin(orgID) || isModerator(orgID));

Разрешить чтение, только если пользователь вошел в систему И является либо администратором, либо модератором.

Доступны полные правила здесь

2. Общее руководство:

Go с чистыми правилами:

isAdmin()
isManager()
isPeon()

Что вы можете легко использовать и прочитать позже:

match /reminders/{reminderId} {
    allow read: if authenticated() && (isAdmin(resource.data.organizationId) || isManager(...) || isPeon(...));
    allow write: if authenticated() && (isAdmin(request.resource.data.organizationId) || isManager(...));
    allow delete: if authenticated() && isAdmin(resource.data.organizationId);
}

Некоторые firestore.rules пример: этот и другой .

Настройка модульного теста (⚠️ важно) для ваших правил, так что проще перебирать его и проверять что все работает как положено. Пример теста здесь , запустите его, используя jest.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...