Bu sayfada, Cloud Firestore Security Rules'i kullanarak istemcilerin bir dokümandaki bazı alanlar üzerinde işlem yapmasına izin veren, diğer alanlar üzerinde işlem yapmasına izin vermeyen kurallar oluşturma hakkında bilgi verilmektedir. Bu bilgiler, Güvenlik Kurallarını Yapılandırma ve Güvenlik Kuralları İçin Koşul Yazma başlıklı makalelerdeki kavramları temel alır.
Bir dokümanda yapılan değişiklikleri doküman düzeyinde değil, alan düzeyinde kontrol etmek isteyebilirsiniz.
Örneğin, bir müşterinin doküman oluşturmasına veya değiştirmesine izin vermek ancak söz konusu dokümandaki belirli alanları düzenlemesine izin vermemek isteyebilirsiniz. Alternatif olarak, bir müşterinin oluşturduğu tüm dokümanların her zaman belirli bir alan grubu içermesini zorunlu kılmak isteyebilirsiniz. Bu kılavuzda, Cloud Firestore Security Rules'ü kullanarak bu görevlerin bazılarını nasıl tamamlayabileceğiniz açıklanmaktadır.
Yalnızca belirli alanlar için okuma erişimine izin verme
Cloud Firestore'te okuma işlemleri doküman düzeyinde gerçekleştirilir. Belgenin tamamını alırsınız veya hiçbir şey almazsınız. Kısmi doküman alınamaz. Kullanıcıların bir doküman içindeki belirli alanları okumasını engellemek için yalnızca güvenlik kurallarını kullanmak mümkün değildir.
Bir dokümanda bazı kullanıcılardan gizlemek istediğiniz belirli alanlar varsa en iyi yöntem bunları ayrı bir dokümana yerleştirmektir. Örneğin, private
alt koleksiyonunda aşağıdaki gibi bir doküman oluşturabilirsiniz:
/calisanlar/{emp_id}
name: "Alice Hamilton",
department: 461,
start_date: <timestamp>
/employees/{emp_id}/private/finances
salary: 80000,
bonus_mult: 1.25,
perf_review: 4.2
Ardından, iki koleksiyon için farklı erişim düzeylerine sahip güvenlik kuralları ekleyebilirsiniz. Bu örnekte, yalnızca Finance
değerine eşit role
özel kimlik doğrulama iddiasına sahip kullanıcıların bir çalışanın finansal bilgilerini görüntüleyebileceğini belirtmek için özel kimlik doğrulama iddialarını kullanıyoruz.
service cloud.firestore {
match /databases/{database}/documents {
// Allow any logged in user to view the public employee data
match /employees/{emp_id} {
allow read: if request.resource.auth != null
// Allow only users with the custom auth claim of "Finance" to view
// the employee's financial data
match /private/finances {
allow read: if request.resource.auth &&
request.resource.auth.token.role == 'Finance'
}
}
}
}
Doküman oluşturma sırasında alanları kısıtlama
Cloud Firestore şemasızdır, yani veritabanı düzeyinde bir dokümanın hangi alanları içerdiğine dair herhangi bir kısıtlama yoktur. Bu esneklik, geliştirmeyi kolaylaştırabilir. Ancak müşterilerin yalnızca belirli alanları içeren veya başka alanların bulunmadığı belgeler oluşturabildiğinden emin olmak istediğiniz zamanlar olabilir.
Bu kuralları, request.resource.data
nesnesinin keys
yöntemini inceleyerek oluşturabilirsiniz. Bu, istemcinin bu yeni belgeye yazmaya çalıştığı tüm alanların listesidir. Bu alan grubunu hasOnly()
veya hasAny()
gibi işlevlerle birleştirerek, kullanıcının Cloud Firestore'a ekleyebileceği belge türlerini kısıtlayan bir mantık ekleyebilirsiniz.
Yeni dokümanlarda belirli alanları zorunlu kılma
Bir restaurant
koleksiyonunda oluşturulan tüm dokümanların en az name
, location
ve city
alanı içerdiğinden emin olmak istediğinizi varsayalım. Bunu yeni dokümandaki anahtar listesinde hasAll()
öğesini çağırarak yapabilirsiniz.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document contains a name
// location, and city field
match /restaurant/{restId} {
allow create: if request.resource.data.keys().hasAll(['name', 'location', 'city']);
}
}
}
Bu, restoranların diğer alanlarla da oluşturulmasına olanak tanır ancak bir müşteri tarafından oluşturulan tüm dokümanların en az bu üç alanı içermesini sağlar.
Yeni dokümanlarda belirli alanları yasaklama
Benzer şekilde, yasaklanmış alanların listesine karşı hasAny()
kullanarak istemcilerin belirli alanları içeren dokümanlar oluşturmasını engelleyebilirsiniz. Bir belge bu alanlardan herhangi birini içeriyorsa bu yöntem doğru olarak değerlendirilir. Bu nedenle, belirli alanları yasaklamak için sonucu reddetmek isteyebilirsiniz.
Örneğin, aşağıdaki örnekte bu alanlar daha sonra bir sunucu çağrısı tarafından ekleneceğinden, istemcilerin average_score
veya rating_count
alanı içeren bir doküman oluşturmasına izin verilmez.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document does *not*
// contain an average_score or rating_count field.
match /restaurant/{restId} {
allow create: if (!request.resource.data.keys().hasAny(
['average_score', 'rating_count']));
}
}
}
Yeni belgeler için izin verilen alanlar listesi oluşturma
Yeni belgelerde belirli alanları yasaklamak yerine, yalnızca yeni belgelerde açıkça izin verilen alanların listesini oluşturabilirsiniz. Ardından, oluşturulan yeni dokümanların yalnızca bu alanları (veya bu alanların bir alt kümesini) içerdiğinden emin olmak için hasOnly()
işlevini kullanabilirsiniz.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document doesn't contain
// any fields besides the ones listed below.
match /restaurant/{restId} {
allow create: if (request.resource.data.keys().hasOnly(
['name', 'location', 'city', 'address', 'hours', 'cuisine']));
}
}
}
Zorunlu ve isteğe bağlı alanları birleştirme
Bazı alanları zorunlu kılmak ve diğerlerine izin vermek için güvenlik kurallarınızda hasAll
ve hasOnly
işlemlerini birlikte kullanabilirsiniz. Örneğin, bu örnekte tüm yeni dokümanların name
, location
ve city
alanlarını içermesi zorunludur ve isteğe bağlı olarak address
, hours
ve cuisine
alanlarına izin verilir.
service cloud.firestore {
match /databases/{database}/documents {
// Allow the user to create a document only if that document has a name,
// location, and city field, and optionally address, hours, or cuisine field
match /restaurant/{restId} {
allow create: if (request.resource.data.keys().hasAll(['name', 'location', 'city'])) &&
(request.resource.data.keys().hasOnly(
['name', 'location', 'city', 'address', 'hours', 'cuisine']));
}
}
}
Gerçek bir senaryoda, kodunuzun kopyalanmasını önlemek ve isteğe bağlı ile zorunlu alanları tek bir listede daha kolay birleştirmek için bu mantığı bir yardımcı işleve taşımak isteyebilirsiniz. Örneğin:
service cloud.firestore {
match /databases/{database}/documents {
function verifyFields(required, optional) {
let allAllowedFields = required.concat(optional);
return request.resource.data.keys().hasAll(required) &&
request.resource.data.keys().hasOnly(allAllowedFields);
}
match /restaurant/{restId} {
allow create: if verifyFields(['name', 'location', 'city'],
['address', 'hours', 'cuisine']);
}
}
}
Güncelleme sırasında alanlar kısıtlanıyor
Yaygın olarak kullanılan bir güvenlik uygulaması, istemcilerin yalnızca bazı alanları düzenlemesine izin vermek olup diğerlerini düzenlememektir. Bu işlemi yalnızca önceki bölümde açıklanan request.resource.data.keys()
listesine bakarak yapamazsınız. Bu liste, güncellemeden sonra dokümanın tümünü temsil ettiğinden ve bu nedenle istemcinin değiştirmediği alanları içerdiğinden.
Ancak diff()
işlevini kullanırsanız request.resource.data
öğesini, güncellemeden önce veritabanındaki dokümanı temsil eden resource.data
nesnesi ile karşılaştırabilirsiniz. Bu işlem, iki farklı harita arasındaki tüm değişiklikleri içeren bir mapDiff
nesnesi oluşturur.
Bu mapDiff üzerinde affectedKeys()
yöntemini çağırarak bir düzenlemede değiştirilen bir dizi alan elde edebilirsiniz. Ardından, bu grubun belirli öğeleri içerip içermediğinden emin olmak için hasOnly()
veya hasAny()
gibi işlevleri kullanabilirsiniz.
Bazı alanların değiştirilmesini önleme
affectedKeys()
tarafından oluşturulan kümede hasAny()
yöntemini kullanıp ardından sonucu olumsuzlayarak, değiştirilmesini istemediğiniz alanları değiştirmeye çalışan tüm istemci isteklerini reddedebilirsiniz.
Örneğin, müşterilerin bir restoranla ilgili bilgileri güncellemesine izin vermek ancak ortalama puanını veya yorum sayısını değiştirmelerine izin vermemek isteyebilirsiniz.
service cloud.firestore {
match /databases/{database}/documents {
match /restaurant/{restId} {
// Allow the client to update a document only if that document doesn't
// change the average_score or rating_count fields
allow update: if (!request.resource.data.diff(resource.data).affectedKeys()
.hasAny(['average_score', 'rating_count']));
}
}
}
Yalnızca belirli alanların değiştirilmesine izin verme
Değiştirilmesini istemediğiniz alanları belirtmek yerine hasOnly()
işlevini kullanarak değiştirilmesini istediğiniz alanların listesini belirtebilirsiniz. Güvenlik kurallarınızda açıkça izin vermediğiniz sürece yeni belge alanlarına yazma işlemine varsayılan olarak izin verilmediğinden bu yöntem genellikle daha güvenli kabul edilir.
Örneğin, average_score
ve rating_count
alanının kullanılmasına izin vermemek yerine, istemcilerin yalnızca name
, location
, city
, address
, hours
ve cuisine
alanlarını değiştirmesine izin veren güvenlik kuralları oluşturabilirsiniz.
service cloud.firestore {
match /databases/{database}/documents {
match /restaurant/{restId} {
// Allow a client to update only these 6 fields in a document
allow update: if (request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(['name', 'location', 'city', 'address', 'hours', 'cuisine']));
}
}
}
Bu, uygulamanızın gelecekteki bir yinelemesinde restoran dokümanlarında bir telephone
alanı varsa siz geri dönüp bu alanı güvenlik kurallarınızdaki hasOnly()
listesine ekleyene kadar bu alanı düzenleme girişimleri başarısız olur.
Alan türlerini zorunlu kılma
Cloud Firestore öğesinin şemasız olmasının bir diğer etkisi de, belirli alanlarda ne tür verilerin depolanabileceği konusunda veritabanı düzeyinde herhangi bir yaptırım uygulanmamasıdır. Ancak bu, is
operatörüyle güvenlik kurallarında zorunlu kılabilirsiniz.
Örneğin, aşağıdaki güvenlik kuralı bir incelemenin score
alanının tam sayı, headline
, content
ve author_name
alanlarının dize, review_date
alanının ise zaman damgası olması gerektiğini zorunlu kılar.
service cloud.firestore {
match /databases/{database}/documents {
match /restaurant/{restId} {
// Restaurant rules go here...
match /review/{reviewId} {
allow create: if (request.resource.data.score is int &&
request.resource.data.headline is string &&
request.resource.data.content is string &&
request.resource.data.author_name is string &&
request.resource.data.review_date is timestamp
);
}
}
}
}
is
operatörü için geçerli veri türleri bool
, bytes
, float
, int
,
list
, latlng
, number
, path
, map
, string
ve timestamp
'dir. is
operatörü constraint
, duration
, set
ve map_diff
veri türlerini de destekler. Ancak bunlar güvenlik kuralları dilinin kendisi tarafından oluşturulduğundan ve istemciler tarafından oluşturulmadığından en pratik uygulamalarda bunları nadiren kullanırsınız.
list
ve map
veri türleri, genel türleri veya tür bağımsız değişkenlerini desteklemez.
Diğer bir deyişle, belirli bir alanın liste veya harita içermesini zorunlu kılmak için güvenlik kurallarını kullanabilirsiniz ancak bir alanın tüm tam sayıların veya tüm dizelerin listesini içermesini zorunlu kılamazsınız.
Benzer şekilde, bir liste veya haritadaki belirli girişler için tür değerlerini zorunlu kılmak üzere güvenlik kurallarını kullanabilirsiniz (sırasıyla parantez gösterimi veya anahtar adlarını kullanarak). Ancak bir harita veya listedeki tüm üyelerin veri türlerini aynı anda zorunlu kılmak için kısayol yoktur.
Örneğin, aşağıdaki kurallar bir dokümanda tags
alanının bir liste içermesini ve ilk girişin dize olmasını sağlar. Ayrıca product
alanının, bir dize olan ürün adını ve tam sayı olan bir miktarı içeren bir harita içermesini sağlar.
service cloud.firestore {
match /databases/{database}/documents {
match /orders/{orderId} {
allow create: if request.resource.data.tags is list &&
request.resource.data.tags[0] is string &&
request.resource.data.product is map &&
request.resource.data.product.name is string &&
request.resource.data.product.quantity is int
}
}
}
}
Alan türleri hem doküman oluştururken hem de güncellerken zorunlu kılınmalıdır. Bu nedenle, güvenlik kurallarınızın hem oluşturma hem de güncelleme bölümlerinde çağırabileceğiniz bir yardımcı işlev oluşturmayı düşünebilirsiniz.
service cloud.firestore {
match /databases/{database}/documents {
function reviewFieldsAreValidTypes(docData) {
return docData.score is int &&
docData.headline is string &&
docData.content is string &&
docData.author_name is string &&
docData.review_date is timestamp;
}
match /restaurant/{restId} {
// Restaurant rules go here...
match /review/{reviewId} {
allow create: if reviewFieldsAreValidTypes(request.resource.data) &&
// Other rules may go here
allow update: if reviewFieldsAreValidTypes(request.resource.data) &&
// Other rules may go here
}
}
}
}
İsteğe bağlı alanlar için türleri zorunlu kılma
foo
'ın bulunmadığı bir belgede request.resource.data.foo
çağrısının hata verdiğini ve bu nedenle bu çağrıyı yapan tüm güvenlik kurallarının isteği reddettiğini unutmayın. Bu durumu request.resource.data
'da get
yöntemini kullanarak çözebilirsiniz. get
yöntemi, haritadan aldığınız alan mevcut değilse bu alan için varsayılan bir bağımsız değişken sağlamanıza olanak tanır.
Örneğin, inceleme dokümanları da doğrulamak istediğiniz isteğe bağlı bir photo_url
alanı ve isteğe bağlı bir tags
alanı içeriyorsa (sırasıyla dize ve liste) reviewFieldsAreValidTypes
işlevini aşağıdaki gibi yeniden yazarak bunu yapabilirsiniz:
function reviewFieldsAreValidTypes(docData) {
return docData.score is int &&
docData.headline is string &&
docData.content is string &&
docData.author_name is string &&
docData.review_date is timestamp &&
docData.get('photo_url', '') is string &&
docData.get('tags', []) is list;
}
Bu, tags
alanının bulunduğu ancak liste olmayan dokümanları reddeder. tags
(veya photo_url
) alanı içermeyen dokümanlara ise izin verir.
Kısmi yazmalara hiçbir zaman izin verilmez
Cloud Firestore Security Rules ile ilgili son bir not da, istemcinin bir dokümanda değişiklik yapmasına izin vermeleri veya düzenlemenin tamamını reddetmeleridir. Dokümanınızdaki bazı alanlara yazma işlemlerini kabul ederken aynı işlemde diğerlerini reddeden güvenlik kuralları oluşturamazsınız.