Kullanıcılar ve gruplar için veri erişimini güvenli hale getirin

Birçok ortak çalışma uygulaması, kullanıcıların farklı verileri okumasına ve yazmasına olanak tanır. izin verir. Örneğin, bir doküman düzenleme uygulamasında kullanıcılar, çalışırken dokümanlarını okumasına ve yazmasına izin vermek engelleme.

Çözüm: Rol Tabanlı Erişim Denetimi

Cloud Firestore'un veri modelinin yanı sıra özel rol tabanlı erişimi uygulamak için güvenlik kurallarını emin olun.

Kullanıcıların, ortak çalışmaya dayalı bir yazma uygulaması oluşturduğunuzu varsayalım. "hikayeler" oluşturabilir ve "yorumlar" :

  • Her hikayenin bir sahibi vardır ve "yazarlar", "yorumcular" ve "okuyucular" ile paylaşılabilir.
  • Okuyucular yalnızca hikayeleri ve yorumları görebilir. Hiçbir şeyi düzenleyemezler.
  • Yorumcular, okuyucuların tüm erişimine sahiptir ve haberlere yorum ekleyebilirler.
  • Yazarlar, yorumcuların tüm erişimine sahiptir ve hikaye içeriklerini de düzenleyebilir.
  • Sahipler, hikayenin herhangi bir bölümünü düzenleyebilir ve diğer kullanıcıların erişimini kontrol edebilir.

Veri Yapısı

Uygulamanızda, her dokümanın temsil ettiği bir stories koleksiyonu olduğunu varsayalım anlatabilmişimdir. Her hikayede, her belgenin mevcut olduğu comments alt koleksiyon da vardır. o hikayeyle ilgili bir yorumdur.

Erişim rollerini takip etmek için bir roles alanı ekleyin. Bu alan rollere kullanıcı kimlikleri:

/Hikayeler/{storyid}

{
  title: "A Great Story",
  content: "Once upon a time ...",
  roles: {
    alice: "owner",
    bob: "reader",
    david: "writer",
    jane: "commenter"
    // ...
  }
}

Yorumlarda, yazarın kullanıcı kimliği ve bazı içerikler olmak üzere yalnızca iki alan bulunur:

/Hikayeler/{storyid}/yorumlar/{commentid}

{
  user: "alice",
  content: "I think this is a great story!"
}

Kurallar

Artık kullanıcılarınızın her bir rol için bunları ayrı olarak Güvenlik Kuralları'nı inceleyin. Bu kurallar, uygulamanın Firebase Auth'u kullanarak request.auth.uid değişkeni kullanıcının kimliğidir.

1. Adım: Hikayeler için boş kurallar içeren temel kural dosyasıyla başlayın ve yorumlar:

service cloud.firestore {
   match /databases/{database}/documents {
     match /stories/{story} {
         // TODO: Story rules go here...

         match /comments/{comment} {
            // TODO: Comment rules go here...
         }
     }
   }
}

2. Adım: Sahiplere aşağıdakilerin üzerinde tam kontrol sağlayan basit bir write kuralı ekleyin: hikayeler. Tanımlanan işlevler, kullanıcı rollerinin belirlenmesine yardımcı olur ve yeni dokümanların geçerli olduğu durumlar:

service cloud.firestore {
   match /databases/{database}/documents {
     match /stories/{story} {
        function isSignedIn() {
          return request.auth != null;
        }

        function getRole(rsc) {
          // Read from the "roles" map in the resource (rsc).
          return rsc.data.roles[request.auth.uid];
        }

        function isOneOfRoles(rsc, array) {
          // Determine if the user is one of an array of roles
          return isSignedIn() && (getRole(rsc) in array);
        }

        function isValidNewStory() {
          // Valid if story does not exist and the new story has the correct owner.
          return resource == null && isOneOfRoles(request.resource, ['owner']);
        }

        // Owners can read, write, and delete stories
        allow write: if isValidNewStory() || isOneOfRoles(resource, ['owner']);

         match /comments/{comment} {
            // ...
         }
     }
   }
}

3. Adım: Her pozisyondaki kullanıcının hikayeleri okumasına ve yorum. Önceki adımda tanımlanan işlevleri kullandığınızda, kuralları korursunuz. kısa ve özlü olmalıdır:

service cloud.firestore {
   match /databases/{database}/documents {
     match /stories/{story} {
        function isSignedIn() {
          return request.auth != null;
        }

        function getRole(rsc) {
          return rsc.data.roles[request.auth.uid];
        }

        function isOneOfRoles(rsc, array) {
          return isSignedIn() && (getRole(rsc) in array);
        }

        function isValidNewStory() {
          return resource == null
            && request.resource.data.roles[request.auth.uid] == 'owner';
        }

        allow write: if isValidNewStory() || isOneOfRoles(resource, ['owner']);

        // Any role can read stories.
        allow read: if isOneOfRoles(resource, ['owner', 'writer', 'commenter', 'reader']);

        match /comments/{comment} {
          // Any role can read comments.
          allow read: if isOneOfRoles(get(/databases/$(database)/documents/stories/$(story)),
                                      ['owner', 'writer', 'commenter', 'reader']);
        }
     }
   }
}

4. adım: Hikaye yazarları, yorumcuları ve sahiplerinin yorum yayınlamasına izin verin. Bu kuralın, yorumun owner değerinin kullanıcının birbirlerinin yorumlarına yazmasını önleyen, istekte bulunan kullanıcı:

service cloud.firestore {
   match /databases/{database}/documents {
     match /stories/{story} {
        function isSignedIn() {
          return request.auth != null;
        }

        function getRole(rsc) {
          return rsc.data.roles[request.auth.uid];
        }

        function isOneOfRoles(rsc, array) {
          return isSignedIn() && (getRole(rsc) in array);
        }

        function isValidNewStory() {
          return resource == null
            && request.resource.data.roles[request.auth.uid] == 'owner';
        }

        allow write: if isValidNewStory() || isOneOfRoles(resource, ['owner'])
        allow read: if isOneOfRoles(resource, ['owner', 'writer', 'commenter', 'reader']);

        match /comments/{comment} {
          allow read: if isOneOfRoles(get(/databases/$(database)/documents/stories/$(story)),
                                      ['owner', 'writer', 'commenter', 'reader']);

          // Owners, writers, and commenters can create comments. The
          // user id in the comment document must match the requesting
          // user's id.
          //
          // Note: we have to use get() here to retrieve the story
          // document so that we can check the user's role.
          allow create: if isOneOfRoles(get(/databases/$(database)/documents/stories/$(story)),
                                        ['owner', 'writer', 'commenter'])
                        && request.resource.data.user == request.auth.uid;
        }
     }
   }
}

5. Adım: Yazarlara hikaye içeriğini düzenleme izni verin ancak hikayeyi düzenleme izni vermeyin dokümanın diğer özelliklerini değiştirebilirsiniz. Bu işlem, write haberleri create, update ve Yazarlar yalnızca haberleri güncelleyebileceği için delete:

service cloud.firestore {
   match /databases/{database}/documents {
     match /stories/{story} {
        function isSignedIn() {
          return request.auth != null;
        }

        function getRole(rsc) {
          return rsc.data.roles[request.auth.uid];
        }

        function isOneOfRoles(rsc, array) {
          return isSignedIn() && (getRole(rsc) in array);
        }

        function isValidNewStory() {
          return request.resource.data.roles[request.auth.uid] == 'owner';
        }

        function onlyContentChanged() {
          // Ensure that title and roles are unchanged and that no new
          // fields are added to the document.
          return request.resource.data.title == resource.data.title
            && request.resource.data.roles == resource.data.roles
            && request.resource.data.keys() == resource.data.keys();
        }

        // Split writing into creation, deletion, and updating. Only an
        // owner can create or delete a story but a writer can update
        // story content.
        allow create: if isValidNewStory();
        allow delete: if isOneOfRoles(resource, ['owner']);
        allow update: if isOneOfRoles(resource, ['owner'])
                      || (isOneOfRoles(resource, ['writer']) && onlyContentChanged());
        allow read: if isOneOfRoles(resource, ['owner', 'writer', 'commenter', 'reader']);

        match /comments/{comment} {
          allow read: if isOneOfRoles(get(/databases/$(database)/documents/stories/$(story)),
                                      ['owner', 'writer', 'commenter', 'reader']);
          allow create: if isOneOfRoles(get(/databases/$(database)/documents/stories/$(story)),
                                        ['owner', 'writer', 'commenter'])
                        && request.resource.data.user == request.auth.uid;
        }
     }
   }
}

Sınırlamalar

Yukarıda gösterilen çözüm, Güvenlik Kuralları'nı kullanarak kullanıcı verilerinin güvenliğini sağlamayı gösterir. ancak aşağıdaki sınırlamalara da dikkat etmelisiniz:

  • Ayrıntı düzeyi: Yukarıdaki örnekte birden fazla rol (yazar ve sahip) aynı dokümana farklı sınırlamalarla yazma erişimine sahip olmalıdır. Daha karmaşık belgelerle bunu yönetmek zor olabilir ve tek bir dokümanı birden çok dokümana bölmek daha iyi olabilir tek bir role ait.
  • Büyük Gruplar: Çok büyük veya karmaşık gruplarla paylaşımda bulunmanız gerekiyorsa Rollerin kendi koleksiyonlarında depolandığı bir sistem yalnızca hedef belgedeki bir alan olarak kullanılabilir.