Bu sayfada, Güvenlik Kurallarını Yapılandırma ve Güvenlik Kuralları İçin Yazma Koşulları sayfalarındaki kavramlar temel alınarak Cloud Firestore Security Rules'nin sorgularla nasıl etkileşimde bulunduğu açıklanmaktadır. Güvenlik kurallarının yazabileceğiniz sorguları nasıl etkilediğini daha ayrıntılı bir şekilde inceler ve sorgularınızın güvenlik kurallarınızla aynı kısıtlamaları kullandığından nasıl emin olacağınızı açıklar. Bu sayfada, sorgu özelliklerine (ör. limit
ve orderBy
) göre sorgulara izin vermek veya sorguları reddetmek için güvenlik kurallarının nasıl yazılacağı da açıklanmaktadır.
Kurallar filtre değildir
Belgeleri almak için sorgu yazarken güvenlik kurallarının filtre olmadığını, sorguların ise ya tamamen ya da hiç çalışmadığını unutmayın. Cloud Firestore, zamandan ve kaynaklardan tasarruf etmenizi sağlamak için bir sorguyu tüm dokümanlarınızdaki gerçek alan değerleri yerine olası sonuç kümesine göre değerlendirir. Bir sorgu, istemcinin okuma izni olmayan belgeleri döndürebilecekse isteğin tamamı başarısız olur.
Sorgular ve güvenlik kuralları
Aşağıdaki örneklerde gösterildiği gibi, sorgularınızı güvenlik kurallarınızın kısıtlamalarına uyacak şekilde yazmanız gerekir.
auth.uid
temelinde dokümanları güvenli hale getirin ve sorgulayın
Aşağıdaki örnekte, bir güvenlik kuralıyla korunan dokümanları almak için sorgunun nasıl yazılacağı gösterilmektedir. story
doküman koleksiyonu içeren bir veritabanı düşünün:
/stories/{storyid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
title
ve content
alanlarına ek olarak, her dokümanda erişim denetimi için kullanılacak author
ve published
alanları da saklanır. Bu örneklerde, uygulamanın author
alanını belgeyi oluşturan kullanıcının UID'si olarak ayarlamak için Firebase Authentication kullandığı varsayılır. Firebase
Authentication, güvenlik kurallarındaki request.auth
değişkenini de doldurur.
Aşağıdaki güvenlik kuralı, her request.auth
için okuma ve yazma erişimini yazarla kısıtlamak üzere resource.data
ve story
değişkenlerini kullanır:
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Only the authenticated user who authored the document can read or write
allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Uygulamanızda, kullanıcıya yazdığı story
belgelerin listesini gösteren bir sayfa olduğunu varsayalım. Bu sayfayı doldurmak için aşağıdaki sorguyu kullanabileceğinizi düşünebilirsiniz. Ancak bu sorgu, güvenlik kurallarınızla aynı kısıtlamaları içermediği için başarısız olur:
Geçersiz: Sorgu kısıtlamaları, güvenlik kuralları kısıtlamalarıyla eşleşmiyor
// This query will fail
db.collection("stories").get()
Sorgu, geçerli kullanıcı aslında her belgenin yazarı olsa bile başarısız olur.story
Bu davranışın nedeni, Cloud Firestore güvenlik kurallarınızı uygularken sorguyu veritabanınızdaki dokümanların gerçek özelliklerine göre değil, olası sonuç kümesine göre değerlendirmesidir. Bir sorgu, güvenlik kurallarınızı ihlal eden belgeler içerebilecekse sorgu başarısız olur.
Buna karşılık, aşağıdaki sorgu başarılı olur. Çünkü güvenlik kurallarıyla aynı author
alanı kısıtlamasını içerir:
Geçerli: Sorgu kısıtlamaları, güvenlik kuralları kısıtlamalarıyla eşleşiyor.
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
Belgeleri güvenli bir şekilde sorgulama
Sorgular ve kurallar arasındaki etkileşimi daha iyi göstermek için aşağıdaki güvenlik kuralları, stories
koleksiyonu için okuma erişimini genişleterek published
alanı true
olarak ayarlanmış story
belgelerinin herhangi bir kullanıcı tarafından okunmasına izin verir.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Anyone can read a published story; only story authors can read unpublished stories
allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
// Only story authors can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Yayınlanmış sayfalarla ilgili sorgu, güvenlik kurallarıyla aynı kısıtlamaları içermelidir:
db.collection("stories").where("published", "==", true).get()
Sorgu kısıtlaması .where("published", "==", true)
, herhangi bir sonuç için resource.data.published
değerinin true
olmasını garanti eder. Bu nedenle, bu sorgu güvenlik kurallarını karşılar ve verileri okumasına izin verilir.
OR
sorgu
Bir kural grubuyla karşılaştırılan mantıksal bir OR
sorgu (or
, in
veya array-contains-any
) değerlendirilirken Cloud Firestore, her karşılaştırma değerini ayrı ayrı değerlendirir. Her karşılaştırma değeri, güvenlik kuralı kısıtlamalarını karşılamalıdır. Örneğin, şu kural için:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
Geçersiz: Sorgu, tüm olası dokümanlar için x > 5
değerini garanti etmiyor.
// These queries will fail
query(db.collection("mydocuments"),
or(where("x", "==", 1),
where("x", "==", 6)
)
)
query(db.collection("mydocuments"),
where("x", "in", [1, 3, 6, 42, 99])
)
Geçerli: Sorgu, x > 5
tüm olası belgeler için geçerli olmasını garanti eder.
query(db.collection("mydocuments"),
or(where("x", "==", 6),
where("x", "==", 42)
)
)
query(db.collection("mydocuments"),
where("x", "in", [6, 42, 99, 105, 200])
)
Sorgularla ilgili kısıtlamaları değerlendirme
Güvenlik kurallarınız, sorguları kısıtlamalarına göre kabul edebilir veya reddedebilir.
request.query
değişkeni, bir sorgunun limit
, offset
ve orderBy
özelliklerini içerir. Örneğin, güvenlik kurallarınız, alınan maksimum belge sayısını belirli bir aralıkla sınırlamayan tüm sorguları reddedebilir:
allow list: if request.query.limit <= 10;
Aşağıdaki kural grubu, sorgulara uygulanan kısıtlamaları değerlendiren güvenlik kurallarının nasıl yazılacağını gösterir. Bu örnek, önceki stories
kurallarını aşağıdaki değişikliklerle genişletir:
- Kural grubu, okuma kuralını
get
velist
kurallarına ayırır. get
kuralı, tek dokümanların alınmasını ortak dokümanlarla veya kullanıcının oluşturduğu dokümanlarla kısıtlar.list
kuralı,get
ile aynı kısıtlamaları sorgular için uygular. Ayrıca sorgu sınırını da kontrol eder ve sınır içermeyen veya 10'dan büyük bir sınıra sahip sorguları reddeder.- Kural kümesi, kod tekrarını önlemek için bir
authorOrPublished()
işlevi tanımlar.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Returns `true` if the requested story is 'published'
// or the user authored the story
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
// Deny any query not limited to 10 or fewer documents
// Anyone can query published stories
// Authors can query their unpublished stories
allow list: if request.query.limit <= 10 &&
authorOrPublished();
// Anyone can retrieve a published story
// Only a story's author can retrieve an unpublished story
allow get: if authorOrPublished();
// Only a story's author can write to a story
allow write: if request.auth.uid == resource.data.author;
}
}
}
Toplama grubu sorguları ve güvenlik kuralları
Sorgular varsayılan olarak tek bir koleksiyonla sınırlandırılır ve yalnızca bu koleksiyondan sonuç alınır. Koleksiyon grubu sorgularıyla, aynı kimliğe sahip tüm koleksiyonlardan oluşan bir koleksiyon grubundan sonuç alabilirsiniz. Bu bölümde, güvenlik kurallarını kullanarak koleksiyon grubu sorgularınızın nasıl güvenli hale getirileceği açıklanmaktadır.
Koleksiyon gruplarına göre dokümanları güvenli bir şekilde sorgulama
Güvenlik kurallarınızda, koleksiyon grubu için bir kural yazarak koleksiyon grubu sorgularına açıkça izin vermeniz gerekir:
rules_version = '2';
ifadesinin kural setinizin ilk satırı olduğundan emin olun. Koleksiyon grubu sorguları için güvenlik kuralları sürüm 2'nin yeni yinelemeli joker karakter{name=**}
davranışı gerekir.match /{path=**}/[COLLECTION_ID]/{doc}
kullanarak koleksiyon grubunuz için bir kural yazın.
Örneğin, forum
dokümanı içeren bir forumu ele alalım. Bu dokümanlar posts
alt koleksiyonlarını içerir:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
Bu uygulamada, gönderilerin sahipleri tarafından düzenlenebilmesini ve kimliği doğrulanmış kullanıcılar tarafından okunabilmesini sağlıyoruz:
service cloud.firestore {
match /databases/{database}/documents {
match /forums/{forumid}/posts/{post} {
// Only authenticated users can read
allow read: if request.auth != null;
// Only the post author can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Kimliği doğrulanmış tüm kullanıcılar, herhangi bir forumdaki yayınları alabilir:
db.collection("forums/technology/posts").get()
Ancak mevcut kullanıcıya tüm forumlardaki yayınlarını göstermek isterseniz ne yapmanız gerekir?
posts
koleksiyonun tümünden sonuç almak için koleksiyon grubu sorgusu kullanabilirsiniz:
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
Güvenlik kurallarınızda, posts
koleksiyon grubu için bir okuma veya liste kuralı yazarak bu sorguya izin vermeniz gerekir:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Authenticated users can query the posts collection group
// Applies to collection queries, collection group queries, and
// single document retrievals
match /{path=**}/posts/{post} {
allow read: if request.auth != null;
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
Ancak bu kuralların, hiyerarşiden bağımsız olarak posts
kimlikli tüm koleksiyonlar için geçerli olacağını unutmayın. Örneğin, bu kurallar aşağıdaki koleksiyonların tümü için geçerlidir:
posts
/posts/{postid}
/forums/{forumid}/posts/{postid}
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
Bir alana göre güvenli toplama grubu sorguları
Tek koleksiyonlu sorgular gibi, koleksiyon grubu sorguları da güvenlik kurallarınız tarafından belirlenen kısıtlamaları karşılamalıdır. Örneğin, yukarıdaki stories
örneğinde yaptığımız gibi her forum gönderisine bir published
alanı ekleyebiliriz:
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
Ardından, posts
koleksiyon grubu için published
durumuna ve author
gönderisine göre kurallar yazabiliriz:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Returns `true` if the requested post is 'published'
// or the user authored the post
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
match /{path=**}/posts/{post} {
// Anyone can query published posts
// Authors can query their unpublished posts
allow list: if authorOrPublished();
// Anyone can retrieve a published post
// Authors can retrieve an unpublished post
allow get: if authorOrPublished();
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth.uid == resource.data.author;
}
}
}
Bu kurallarla Web, Apple ve Android istemcileri aşağıdaki sorguları yapabilir:
Herkes forumdaki yayınlanmış gönderileri alabilir:
db.collection("forums/technology/posts").where('published', '==', true).get()
Herkes, bir yazarın tüm forumlardaki yayınlanmış gönderilerini alabilir:
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
Yazarlar, tüm forumlardaki yayınlanmış ve yayınlanmamış gönderilerini alabilir:
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
Koleksiyon grubuna ve doküman yoluna göre dokümanları güvenli bir şekilde sorgulama
Bazı durumlarda, doküman yoluna göre koleksiyon grubu sorgularını kısıtlamak isteyebilirsiniz. Bu kısıtlamaları oluşturmak için, alan tabanlı belge güvenliği ve sorgulama ile ilgili aynı teknikleri kullanabilirsiniz.
Çeşitli borsa ve kripto para borsalarındaki her kullanıcının işlemlerini takip eden bir uygulamayı ele alalım:
/users/{userid}/exchange/{exchangeid}/transactions/{transaction}
{
amount: 100,
exchange: 'some_exchange_name',
timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
user: "some_auth_id",
}
user
alanına dikkat edin. Bir transaction
belgenin yolundan hangi kullanıcının sahibi olduğunu bilsek de bu bilgiyi her transaction
belgede kopyalarız. Bunun nedeni, bu bilgiyi kullanarak iki işlem yapabilmemizdir:
Doküman yolunda belirli bir
/users/{userid}
içeren dokümanlarla sınırlı koleksiyon grubu sorguları yazın. Örneğin:var user = firebase.auth().currentUser; // Return current user's last five transactions across all exchanges db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)
transactions
koleksiyon grubundaki tüm sorgular için bu kısıtlamayı zorunlu kılın. Böylece bir kullanıcı, başka bir kullanıcınıntransaction
belgelerini alamaz.
Bu kısıtlamayı güvenlik kurallarımızda uygularız ve user
alanı için veri doğrulamayı dahil ederiz:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{path=**}/transactions/{transaction} {
// Authenticated users can retrieve only their own transactions
allow read: if resource.data.user == request.auth.uid;
}
match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
// Authenticated users can write to their own transactions subcollections
// Writes must populate the user field with the correct auth id
allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
}
}
}
Sonraki adımlar
- Rol tabanlı erişim denetimiyle ilgili daha ayrıntılı bir örnek için Kullanıcılar ve Gruplar İçin Veri Erişimini Güvenli Hale Getirme başlıklı makaleyi inceleyin.
- Güvenlik kuralları referansını okuyun.