Yetkilendirme ve doğrulama ile Data Connect'i güvence altına alma

Firebase Data Connect aşağıdaki özelliklerle güçlü bir istemci tarafı güvenliği sağlar:

  • Mobil ve web istemcisi yetkilendirmesi
  • Ayrı ayrı sorgu ve mutasyon düzeyinde yetkilendirme kontrolleri
  • Firebase App Check ile uygulama onayı.

Data Connect, bu güvenliği şu özelliklerle genişletir:

  • Sunucu tarafı yetkilendirme
  • IAM ile Firebase projesi ve Cloud SQL kullanıcı güvenliği.

İstemci sorgularını ve mutasyonlarını yetkilendirme

Data Connect, Firebase Authentication ile tamamen entegre olduğundan verilerinize erişen kullanıcılarla (kimlik doğrulama) ilgili zengin verileri, bu kullanıcıların hangi verilere erişebileceği (yetkilendirme) konusundaki tasarımınızda kullanabilirsiniz.

Data Connect, sorgular ve mutasyonlar için @auth yönergesi sağlar. Bu yönerge, işlemi yetkilendirmek için gereken kimlik doğrulama düzeyini ayarlamanıza olanak tanır. Bu kılavuzda, @auth yönergesi örneklerle açıklanmaktadır.

Ayrıca, Data Connect mutasyonlara yerleştirilmiş sorguların yürütülmesini destekler. Böylece, veritabanınızda depoladığınız ek yetkilendirme ölçütlerini alabilir ve bu ölçütleri, kapsayan mutasyonların yetkili olup olmadığını belirlemek için @check yönergelerinde kullanabilirsiniz. Bu yetkilendirme durumunda, @redact yönergesi, sorgu sonuçlarının kablo protokolünde istemcilere döndürülüp döndürülmeyeceğini ve oluşturulan SDK'larda yerleştirilmiş sorgunun atlanıp atlanmayacağını kontrol etmenize olanak tanır. Bu yönergelerin örneklerle birlikte tanıtımını inceleyin.

@auth direktifini anlama

Birçok yaygın erişim senaryosunu kapsayan önceden ayarlanmış çeşitli erişim düzeylerinden birini izlemek için @auth yönergesini parametrelendirebilirsiniz. Bu düzeyler, PUBLIC (herhangi bir kimlik doğrulama olmadan tüm istemcilerden gelen sorgulara ve mutasyonlara izin verir) ile NO_ACCESS (Firebase Admin SDK'sını kullanan ayrıcalıklı sunucu ortamları dışındaki sorgulara ve mutasyonlara izin vermez) arasında değişir. Bu seviyelerin her biri Firebase Authentication tarafından sağlanan kimlik doğrulama akışlarıyla ilişkilidir.

Seviye Tanım
PUBLIC İşlem, kimlik doğrulama yapılarak veya yapılmadan herkes tarafından gerçekleştirilebilir.
PUBLIC İşlem, kimlik doğrulama yapılarak veya yapılmadan herkes tarafından gerçekleştirilebilir.
USER_ANON Firebase Authentication ile anonim olarak giriş yapanlar da dahil olmak üzere tanımlanan tüm kullanıcılar sorgu veya mutasyon gerçekleştirmeye yetkilidir.
USER Firebase Authentication ile giriş yapan tüm kullanıcılar, anonim giriş yapan kullanıcılar hariç sorgu veya mutasyon gerçekleştirmek için yetkilidir.
USER_EMAIL_VERIFIED Doğrulanmış bir e-posta adresiyle Firebase Authentication üzerinden giriş yapan tüm kullanıcılar sorgu veya mutasyon gerçekleştirmeye yetkilidir.
NO_ACCESS Bu işlem, Admin SDK bağlamı dışında yürütülemez.

Bu önceden ayarlanmış erişim düzeylerini başlangıç noktası olarak kullanarak, @auth yönergesinde where filtreleri ve sunucuda değerlendirilen Common Expression Language (CEL) ifadelerini kullanarak karmaşık ve güçlü yetkilendirme kontrolleri tanımlayabilirsiniz.

@auth

Yaygın yetkilendirme senaryolarını uygulamak için @auth yönergesini kullanın

Önceden ayarlanmış erişim düzeyleri, yetkilendirme için başlangıç noktasıdır.

USER erişim düzeyi, başlangıç için en yaygın olarak kullanılan temel düzeydir.

Tamamen güvenli erişim, USER düzeyinin yanı sıra kullanıcı özelliklerini, kaynak özelliklerini, rolleri ve diğer kontrolleri inceleyen filtreler ve ifadeler üzerine kurulur. USER_ANON ve USER_EMAIL_VERIFIED seviyeleri, USER durumunun varyasyonlarıdır.

İfade söz dizimi, işlemlerde iletilen kimlik doğrulama verilerini temsil eden bir auth nesnesi kullanarak verileri değerlendirmenize olanak tanır. Bu nesne, hem kimlik doğrulama jetonlarındaki standart verileri hem de jetonlardaki özel verileri içerir. auth nesnesinde kullanılabilen alanların listesi için referans bölümüne bakın.

Elbette, PUBLIC ile başlamanın doğru erişim düzeyi olduğu kullanım alanları da vardır. Erişim düzeyi her zaman başlangıç noktasıdır ve sağlam bir güvenlik için ek filtreler ve ifadeler gerekir.

Bu kılavuzda artık USER ve PUBLIC üzerinde nasıl geliştirme yapılacağına dair örnekler verilmektedir.

İlham verici bir örnek

Aşağıdaki en iyi uygulama örnekleri, belirli içeriklerin ödeme planı arkasında kilitlendiği bir blog platformunun aşağıdaki şemasına atıfta bulunmaktadır.

Bu tür bir platform büyük olasılıkla Users ve Posts modelini kullanır.

type User @table(key: "uid") {
  uid: String!
  name: String
  birthday: Date
  createdAt: Timestamp! @default(expr: "request.time")
}

type Post @table {
  author: User!
  text: String!
  # "one of 'draft', 'public', or 'pro'"
  visibility: String! @default(value: "draft")
  # "the time at which the post should be considered published. defaults to
  # immediately"
  publishedAt: Timestamp! @default(expr: "request.time")
  createdAt: Timestamp! @default(expr: "request.time")
  updatedAt: Timestamp! @default(expr: "request.time")
}

Kullanıcıya ait kaynaklar

Firebase, aşağıdaki durumlarda kullanıcının bir kaynağın sahipliğini (Posts sahipliği) test eden filtreler ve ifadeler yazmanızı önerir.

Aşağıdaki örneklerde, kimlik doğrulama jetonlarındaki veriler ifadeler kullanılarak okunur ve karşılaştırılır. Tipik olarak, depolanmış bir authorUid değerini kimlik doğrulama jetonunda iletilen auth.uid (kullanıcı kimliği) ile karşılaştırmak için where: {authorUid: {eq_expr: "auth.uid"}} gibi ifadeler kullanılır.

Oluştur

Bu yetkilendirme uygulaması, sonraki yetkilendirme testlerinde karşılaştırmaya olanak tanımak için kimlik doğrulama jetonundaki auth.uid değerini her yeni Post öğesine authorUid alanı olarak ekleyerek başlar.

# Create a new post as the current user
mutation CreatePost($text: String!, $visibility: String) @auth(level: USER) {
  post_insert(data: {
    # set the author's uid to the current user uid
    authorUid_expr: "auth.uid"
    text: $text
    visibility: $visibility
  })
}
Güncelle

Bir istemci Post güncellemeye çalıştığında, iletilen auth.uid değerini depolanan authorUid değeriyle karşılaştırarak test edebilirsiniz.

# Update one of the current user's posts
mutation UpdatePost($id: UUID!, $text: String, $visibility: String) @auth(level:USER) {
  post_update(
    # only update posts whose author is the current user
    first: { where: {
      id: {eq: $id}
      authorUid: {eq_expr: "auth.uid"}
    }}
    data: {
      text: $text
      visibility: $visibility
      # insert the current server time for updatedAt
      updatedAt_expr: "request.time"
    }
  )
}
Sil

Silme işlemlerini yetkilendirmek için de aynı teknik kullanılır.

# Delete one of the current user's posts
mutation DeletePost($id: UUID!) @auth(level: USER) {
  post_delete(
    # only delete posts whose author is the current user
    first: { where: {
      id: {eq: $id}
      authorUid: {eq_expr: "auth.uid"}
    }}
  )
}
# Common display information for a post
fragment DisplayPost on Post {
  id, text, createdAt, updatedAt
  author { uid, name }
}
Liste
# List all posts belonging to the current user
query ListMyPosts @auth(level: USER) {
  posts(where: {
    userUid: {eq_expr: "auth.uid"}
  }) {
    # See the fragment above
    ...DisplayPost
    # also show visibility since it is user-controlled
    visibility
  }
}
Get
# Get a post only if it belongs to the current user
query GetMyPost($id: UUID!) @auth(level: USER) {
  post(key: {id: $id},
    first: {where: {
      id: {eq: $id}
      authorUid: {eq_expr: "auth.uid"}}
      }}, {
      # See the fragment above
      ...DisplayPost
      # also show visibility since it is user-controlled
      visibility
  }
}

Verileri Filtreleme

Data Connect'nın yetkilendirme sistemi, PUBLIC gibi önceden ayarlanmış erişim düzeyleriyle birlikte karmaşık filtreler yazmanıza ve kimlik doğrulama jetonlarından gelen verileri kullanmanıza olanak tanır.

Yetkilendirme sistemi, aşağıdaki örneklerin bazılarında gösterildiği gibi, temel erişim düzeyi olmadan yalnızca ifadeler kullanmanıza da olanak tanır.

Kaynak özelliklerine göre filtreleme

Burada, temel güvenlik düzeyi PUBLIC olarak ayarlandığından yetkilendirme, kimlik doğrulama jetonlarına dayalı değildir. Ancak veritabanımızdaki kayıtları açıkça herkese açık erişime uygun olarak ayarlayabiliriz. Veritabanımızda Post kaydın olduğunu ve visibility kaydın "Herkese açık" olarak ayarlandığını varsayalım.

# List all posts marked as 'public' visibility
query ListPublicPosts @auth(level: PUBLIC) {
  posts(where: {
    # Test that visibility is "public"
    visibility: {eq: "public"}
    # Only display articles that are already published
    publishedAt: {lt_expr: "request.time"}
  }) {
    # see the fragment above
    ...DisplayPost
  }
}
Kullanıcı hak taleplerine göre filtreleme

Burada, uygulamanızın "pro" planındaki kullanıcıları tanımlamak için kimlik doğrulama jetonlarına iletilen özel kullanıcı talepleri ayarladığınızı varsayalım. Bu kullanıcılar, kimlik doğrulama jetonunda auth.token.plan alanı ile işaretlenir. İfadeleriniz bu alana göre test edilebilir.

# List all public or pro posts, only permitted if user has "pro" plan claim
query ProListPosts @auth(expr: "auth.token.plan == 'pro'") {
  posts(where: {
    # display both public posts and "pro" posts
    visibility: {in: ['public', 'pro']},
    # only display articles that are already published
    publishedAt: {lt_expr: "request.time"},
  }) {
    # see the fragment above
    ...DisplayPost
    # show visibility so pro users can see which posts are pro\
    visibility
  }
}
Sıraya ve sınıra göre filtreleme

Alternatif olarak, Post kayıtlarında visibility değerini ayarlayarak bu kayıtların "pro" kullanıcılar için kullanılabilen içerikler olduğunu belirtebilirsiniz. Ancak verilerin önizleme veya teaser listelenmesi için döndürülen kayıt sayısını daha da sınırlayabilirsiniz.

# Show 2 oldest Pro post as a preview
query ProTeaser @auth(level: USER) {
  posts(
    where: {
      # show only pro posts
      visibility: {eq: "pro"}
      # that have already been published more than 30 days ago
      publishedAt: {lt_time: {now: true, sub: {days: 30}}}
    },
    # order by publish time
    orderBy: [{publishedAt: DESC}],
    # only return two posts
    limit: 2
  ) {
    # See the fragment above
    ...DisplayPost
  }
}
Role göre filtreleme

Özel talebiniz bir admin rolü tanımlıyorsa işlemleri buna göre test edip yetkilendirebilirsiniz.

# List all posts unconditionally iff the current user has an admin claim
query AdminListPosts @auth(expr: "auth.token.admin == true") {
  posts { ...DisplayPost }
}

Yetkilendirme verilerini aramak için @check ve @redact yönergelerini ekleyin.

Yaygın bir yetkilendirme kullanım alanında, özel yetkilendirme rolleri veritabanınızda (ör. özel bir izin tablosunda) depolanır ve bu roller, veri oluşturma, güncelleme veya silme mutasyonlarını yetkilendirmek için kullanılır.

Yetkilendirme verisi aramalarını kullanarak bir kullanıcı kimliğine göre rolleri sorgulayabilir ve değişikliğin yetkilendirilip yetkilendirilmediğine karar vermek için CEL ifadelerini kullanabilirsiniz. Örneğin, yetkili bir istemcinin film başlıklarını güncellemesine olanak tanıyan bir UpdateMovieTitle mutasyonu yazmak isteyebilirsiniz.

Bu tartışmanın geri kalanında, film incelemesi uygulama veritabanının MoviePermission tablosunda bir yetkilendirme rolü depoladığını varsayalım.

# MoviePermission
# Suppose a user has an authorization role with respect to records in the Movie table
type MoviePermission @table(key: ["movie", "user"]) {
  movie: Movie! # implies another field: movieId: UUID!
  user: User!
  role: String!
}

Mutasyonlarda kullanma

Aşağıdaki örnek uygulamada, UpdateMovieTitle mutasyonu, MoviePermission kaynağından veri almak için query alanını ve işlemin güvenli ve sağlam olmasını sağlamak için aşağıdaki yönergeleri içerir:

  • Tüm yetkilendirme sorgularının ve kontrollerinin @transaction tamamlanmasını veya atomik olarak başarısız olmasını sağlayan bir yönerge.
  • Sorgu sonuçlarını yanıttan çıkarmak için @redact yönergesi. Bu, yetkilendirme kontrolümüzün Data Connect sunucusunda yapıldığı ancak hassas verilerin istemciye gösterilmediği anlamına gelir.
  • Sorgu sonuçlarındaki yetkilendirme mantığını değerlendirmek için kullanılan bir çift @check yönerge (ör. belirli bir kullanıcı kimliğinin değişiklik yapmak için uygun role sahip olup olmadığını test etme).

mutation UpdateMovieTitle($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
  # Step 1: Query and check
  query @redact {
    moviePermission( # Look up a join table called MoviePermission with a compound key.
      key: {movieId: $movieId, userId_expr: "auth.uid"}
    # Step 1a: Use @check to test if the user has any role associated with the movie
    # Here the `this` binding refers the lookup result, i.e. a MoviePermission object or null
    # The `this != null` expression could be omitted since rejecting on null is default behavior
    ) @check(expr: "this != null", message: "You do not have access to this movie") {
      # Step 1b: Check if the user has the editor role for the movie
      # Next we execute another @check; now `this` refers to the contents of the `role` field
      role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}
this

Sorgularda kullanma

Yetkilendirme verisi aramaları, sorguları rollere veya diğer kısıtlamalara göre kısıtlamak için de kullanışlıdır.

Aşağıdaki örnekte de MoviePermission şeması kullanılmaktadır. Sorgu, bir istekte bulunanın, filmleri düzenleyebilen kullanıcıları görüntülemek için uygun bir "yönetici" rolüne sahip olup olmadığını kontrol eder.

query GetMovieEditors($movieId: UUID!) @auth(level: PUBLIC) {
  moviePermission(key: { movieId: $movieId, userId_expr: "auth.uid" }) @redact {
    role @check(expr: "this == 'admin'", message: "You must be an admin to view all editors of a movie.")
  }
  moviePermissions(where: { movieId: { eq: $movieId }, role: { eq: "editor" } }) {
    user {
      id
      username
    }
  }
}
this

Yetkilendirmede kaçınılması gereken anti-kalıplar

Önceki bölümde, @auth yönergesini kullanırken izlenecek kalıplar ele alınmıştır.

Ayrıca kaçınmanız gereken önemli antipattern'ler hakkında da bilgi sahibi olmalısınız.

Kullanıcı özelliği kimliklerini ve kimlik doğrulama jetonu parametrelerini sorgu ve mutasyon bağımsız değişkenlerinde iletmekten kaçının

Firebase Authentication, kimlik doğrulama akışlarını sunmak ve kayıtlı kullanıcı kimlikleri ile kimlik doğrulama jetonlarında depolanan çok sayıda alan gibi kimlik doğrulama verilerini güvenli bir şekilde yakalamak için kullanılan güçlü bir araçtır.

Kullanıcı kimliklerinin ve kimlik doğrulama jetonu verilerinin sorgu ve mutasyon bağımsız değişkenlerinde iletilmesi önerilen bir uygulama değildir.

# Antipattern!
# This incorrectly allows any user to view any other user's posts
query AllMyPosts($userId: String!) @auth(level: USER) {
  posts(where: {authorUid: {eq: $userId}}) {
    id, text, createdAt
  }
}

USER erişim düzeyini filtre olmadan kullanmaktan kaçının

Kılavuzda birkaç kez belirtildiği gibi, USER, USER_ANON, USER_EMAIL_VERIFIED gibi temel erişim düzeyleri, yetkilendirme kontrolleri için temel ve başlangıç noktalarıdır. Bunlar filtreler ve ifadelerle geliştirilebilir. Bu düzeyleri, isteği hangi kullanıcının gerçekleştirdiğini kontrol eden ilgili bir filtre veya ifade olmadan kullanmak, esasen PUBLIC düzeyini kullanmaya eşdeğerdir.

# Antipattern!
# This incorrectly allows any user to view all documents
query ListDocuments @auth(level: USER) {
  documents {
    id
    title
    text
  }
}

Prototip oluşturma için PUBLIC veya USER erişim düzeyini kullanmaktan kaçının

Geliştirme sürecini hızlandırmak için tüm işlemleri PUBLIC erişim düzeyine veya USER erişim düzeyine ayarlamak cazip gelebilir. Bu sayede tüm işlemler yetkilendirilir ve kodunuzu hızlıca test edebilirsiniz.

Bu şekilde ilk prototipleme işlemini tamamladığınızda NO_ACCESS'dan PUBLIC ve USER seviyeleriyle üretime hazır yetkilendirmeye geçmeye başlayın. Ancak bu kılavuzda gösterildiği gibi ek mantık eklemeden bunları PUBLIC veya USER olarak dağıtmayın.

# Antipattern!
# This incorrectly allows anyone to delete any post
mutation DeletePost($id: UUID!) @auth(level: PUBLIC) {
  post: post_delete(
    id: $id,
  )
}

Yetkilendirmeyi doğrulanmamış e-posta adreslerine dayandırmaktan kaçının

Belirli bir alan adındaki kullanıcılara erişim izni vermek, erişimi sınırlamanın harika bir yoludur. Ancak, oturum açma sırasında herkes bir e-postanın sahibi olduğunu iddia edebilir. Yalnızca Firebase Authentication ile doğrulanmış e-posta adreslerine erişim izni verdiğinizden emin olun.

# Antipattern!
# Anyone can claim an email address during sign-in
mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email.endsWith('@example.com')") {
  post_insert(data: {
    # set the author's uid to the current user uid
    authorUid_expr: "auth.uid"
    text: $text
    visibility: $visibility
  })
}

Ayrıca auth.token.email_verified

mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email_veri&&fied  auth.token.email.endsWith('@example.com')") {
  post_insert(data: {
    # set the author's uid to the current user uid
    authorUid_expr: "auth.uid"
    text: $text
    visibility: $visibility
  })
}

Firebase CLI ile yetkilendirmeyi denetleme

Daha önce belirtildiği gibi, PUBLIC ve USER gibi önceden ayarlanmış erişim düzeyleri, güçlü yetkilendirme için başlangıç noktasıdır ve ek filtre ile ifade tabanlı yetkilendirme kontrolleriyle birlikte kullanılmalıdır. Kullanım alanı dikkatlice değerlendirilmeden tek başına kullanılmamalıdır.

Data Connect, Firebase CLI'dan firebase deploy kullanarak sunucuya dağıtım yaptığınızda bağlayıcı kodunuzu analiz ederek yetkilendirme stratejinizi denetlemenize yardımcı olur. Kod tabanınızı incelemek için bu denetimden yararlanabilirsiniz.

Bağlayıcılarınızı dağıttığınızda KSA, bağlayıcınızdaki mevcut, değiştirilmiş ve yeni işlem kodu için değerlendirmeler oluşturur.

Değiştirilen ve yeni işlemler için CLI, yeni işlemlerinizde belirli erişim düzeylerini kullandığınızda veya mevcut işlemleri bu erişim düzeylerini kullanacak şekilde değiştirdiğinizde uyarılar yayınlar ve onayınızı ister.

Uyarılar ve istemler her zaman şu durumlarda gösterilir:

  • PUBLIC

Ayrıca, auth.uid kullanarak filtrelerle artırmadığınızda aşağıdaki erişim düzeylerinde uyarılar ve istemler gösterilir:

  • USER
  • USER_ANON
  • USER_EMAIL_VERIFIED

@auth(insecureReason:) bağımsız değişkeniyle güvenli olmayan işlem uyarılarını engelleme

Çoğu durumda, PUBLIC ve USER* erişim düzeylerini kullanmanın tamamen uygun olduğu sonucuna varırsınız.

Bağlayıcınız çok sayıda işlem içerdiğinde, normalde uyarıyı tetikleyecek ancak doğru erişim düzeyine sahip olduğunuzu bildiğiniz işlemleri atlayan daha net ve daha alakalı bir güvenlik denetimi çıktısı isteyebilirsiniz.

@auth(insecureReason:) ile bu tür işlemler için uyarıları devre dışı bırakabilirsiniz. Örneğin:

query listItem @auth(level: PUBLIC, insecureReason: "This operation is safe to expose to the public.")
  {
    items {
      id name
    }
  }

Uygulama onayı için Firebase App Check kullanma

Kimlik doğrulama ve yetkilendirme, Data Connectgüvenliğin kritik bileşenleridir. Kimlik doğrulama ve yetkilendirme, uygulama onayıyla birlikte çok güçlü bir güvenlik çözümü sunar.

Firebase App Check aracılığıyla onaylama sayesinde, uygulamanızı çalıştıran cihazlar, Data Connect işlemlerinin gerçek uygulamanızdan, isteklerin ise gerçek ve kurcalanmamış bir cihazdan geldiğini onaylayan bir uygulama veya cihaz onaylama sağlayıcısı kullanır. Bu onay, uygulamanızın Data Connect'ya yaptığı her isteğe eklenir.

App Check için Data Connect özelliğini nasıl etkinleştireceğinizi ve istemci SDK'sını uygulamanıza nasıl ekleyeceğinizi öğrenmek için App Check genel bakışına göz atın.

@auth(level) yönergesi için kimlik doğrulama düzeyleri

Aşağıdaki tabloda tüm standart erişim düzeyleri ve bunların CEL karşılıkları listelenmiştir. Kimlik doğrulama düzeyleri genişten dara doğru listelenir. Her düzey, aşağıdaki düzeylerle eşleşen tüm kullanıcıları kapsar.

Seviye Tanım
PUBLIC İşlem, kimlik doğrulama yapılarak veya yapılmadan herkes tarafından gerçekleştirilebilir.

Dikkat edilmesi gerekenler: Veriler herhangi bir kullanıcı tarafından okunabilir veya değiştirilebilir. Firebase, ürün veya medya listelemeleri gibi herkese açık olarak göz atılabilen veriler için bu yetkilendirme düzeyini önerir. En iyi uygulama örneklerine ve alternatiflere göz atın.

@auth(expr: "true")

@auth filtreleri ve ifadeleri bu erişim düzeyiyle birlikte kullanılamaz. Bu tür ifadeler 400 hatalı istek hatasıyla başarısız olur.
USER_ANON Firebase Authentication ile anonim olarak giriş yapanlar da dahil olmak üzere tanımlanan tüm kullanıcılar sorgu veya mutasyon gerçekleştirmeye yetkilidir.

Not: USER_ANON, USER öğesinin üst kümesidir.

Dikkat edilmesi gerekenler: Bu yetkilendirme düzeyi için sorgularınızı ve mutasyonlarınızı dikkatli bir şekilde tasarlamanız gerektiğini unutmayın. Bu düzey, kullanıcının Authentication ile anonim olarak oturum açmasına (otomatik oturum açma yalnızca kullanıcı cihazına bağlıdır) olanak tanır ve verilerin kullanıcıya ait olup olmadığı gibi diğer kontrolleri kendi başına gerçekleştirmez. En iyi uygulama örneklerini ve alternatiflerini inceleyin.

Authentication anonim giriş akışları uid yayınladığından, USER_ANON düzeyi

@auth(expr: "auth.uid != nil") ile eşdeğerdir.
USER Firebase Authentication ile giriş yapan tüm kullanıcılar, anonim giriş yapan kullanıcılar hariç sorgu veya mutasyon gerçekleştirmek için yetkilidir.

Dikkat edilmesi gerekenler: Bu yetkilendirme düzeyi için sorgularınızı ve mutasyonlarınızı dikkatli bir şekilde tasarlamanız gerektiğini unutmayın. Bu düzeyde yalnızca kullanıcının Authentication ile oturum açtığı kontrol edilir. Verilerin kullanıcıya ait olup olmadığı gibi başka kontroller yapılmaz. En iyi uygulama örneklerine ve alternatiflere bakın.

@auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")" etiketine eş değer
USER_EMAIL_VERIFIED Doğrulanmış bir e-posta adresiyle Firebase Authentication üzerinden giriş yapan tüm kullanıcılar sorgu veya mutasyon gerçekleştirmeye yetkilidir.

Dikkat edilmesi gerekenler: E-posta doğrulaması Authentication kullanılarak yapıldığından daha sağlam bir Authentication yöntemine dayanır. Bu nedenle, bu düzey USER veya USER_ANON'ye kıyasla ek güvenlik sağlar. Bu düzey yalnızca kullanıcının doğrulanmış bir e-posta adresiyle Authentication ile oturum açtığını kontrol eder ve verilerin kullanıcıya ait olup olmadığı gibi diğer kontrolleri kendi başına gerçekleştirmez. En iyi uygulama örneklerine ve alternatiflere göz atın.

@auth(expr: "auth.uid != nil && auth.token.email_verified")" etiketine eş değer
NO_ACCESS Bu işlem, Admin SDK bağlamı dışında yürütülemez.

@auth(expr: "false") etiketine eş değer

@auth(expr) için CEL Referansı

Bu kılavuzun başka yerlerindeki örneklerde gösterildiği gibi, Data Connect için yetkilendirmeyi kontrol etmek üzere @auth(expr:) ve @check yönergelerini kullanarak Common Expression Language (CEL) içinde tanımlanan ifadeleri kullanabilirsiniz ve kullanmanız gerekir.

Bu bölümde, bu yönergeler için ifadeler oluşturmayla ilgili CEL söz dizimi ele alınmaktadır.

CEL ile ilgili tüm referans bilgileri CEL spesifikasyonunda verilmiştir.

Sorgularda ve mutasyonlarda iletilen test değişkenleri

@auth(expr) söz dizimi, sorgulardaki ve mutasyonlardaki değişkenlere erişmenize ve bunları test etmenize olanak tanır.

Örneğin, $status gibi bir işlem değişkenini vars.status kullanarak ekleyebilirsiniz.

mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")

İfadelerde kullanılabilen veriler: request, response, this

Verileri şu amaçlarla kullanırsınız:

  • @auth(expr:) ve @check(expr:) yönergelerinde CEL ifadeleriyle değerlendirme
  • Sunucu ifadeleri kullanılarak atama, <field>_expr.

Hem @auth(expr:) hem de @check(expr:) CEL ifadeleri aşağıdakileri değerlendirebilir:

  • request.operationName
  • vars (request.variables için diğer ad)
  • auth (request.auth için diğer ad)

Değişikliklerde aşağıdakilerin içeriklerine erişebilir ve bunları atayabilirsiniz:

  • response (çok adımlı mantıktaki kısmi sonuçları kontrol etmek için)

Ayrıca, @check(expr:) ifadeleri şunları değerlendirebilir:

  • this (geçerli alanın değeri)
  • response (çok adımlı mantıktaki kısmi sonuçları kontrol etmek için)

The request.operationName bağlaması

request.operarationName bağlaması, işlem türünü (sorgu veya mutasyon) depolar.

vars bağlaması (request.vars)

vars bağlaması, ifadelerinizin sorgunuzda veya mutasyonunuzda iletilen tüm değişkenlere erişmesine olanak tanır.

vars.<variablename> ifadesini, tam nitelikli request.variables.<variablename> için takma ad olarak kullanabilirsiniz:

# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")

auth bağlama (request.auth)

Authentication, verilerinize erişim isteğinde bulunan kullanıcıları tanımlar ve bu bilgileri, ifadelerinizde kullanabileceğiniz bir bağlama olarak sağlar.

Filtrelerinizde ve ifadelerinizde auth yerine request.auth takma adını kullanabilirsiniz.

Yetkilendirme bağlaması aşağıdaki bilgileri içerir:

  • uid: İstekte bulunan kullanıcıya atanan benzersiz kullanıcı kimliği.
  • token: Authentication tarafından toplanan değerlerin haritası.

auth.token içeriği hakkında daha fazla bilgi için Kimlik doğrulama jetonlarındaki veriler başlıklı makaleyi inceleyin.

response bağlaması

response bağlaması, bir sorguya veya mutasyona yanıt olarak sunucu tarafından veriler oluşturulurken oluşturulan verileri içerir.

İşlem devam ederken her adım başarıyla tamamlandıkça response, başarıyla tamamlanan adımlardan gelen yanıt verilerini içerir.

response bağlaması, ilişkili işleminin şekline göre yapılandırılır. Bu yapılandırmaya iç içe yerleştirilmiş (birden fazla) alanlar ve (varsa) yerleştirilmiş sorgular dahildir.

Yerleştirilmiş sorgu yanıtı verilerine eriştiğinizde alanların, yerleştirilmiş sorguda istenen verilere bağlı olarak herhangi bir veri türünü içerebileceğini unutmayın. _insert ve _delete gibi mutasyon alanları tarafından döndürülen verilere eriştiğinizde bu veriler UUID anahtarları, silme sayısı ve boş değerler içerebilir (bkz. mutasyon referansı).

Örneğin:

  • Yerleştirilmiş bir sorgu içeren bir mutasyonda, response bağlama, response.query.<fieldName>.<fieldName>.... konumunda arama verileri içerir. Bu durumda response.query.todoList ve response.query.todoList.priority.
mutation CheckTodoPriority(
  $uniqueListName: String!
) {
  # This query is identified as `response.query`
  query @check(expr: "response.query.todoList.priority == 'high'", message: "This list is not for high priority items!") {
    # This field is identified as `response.query.todoList`
    todoList(where: { name: $uniqueListName }) {
      # This field is identified as `response.query.todoList.priority`
      priority
    }
  }
}
  • Çok adımlı bir mutasyonda (ör. birden fazla _insert alanı içeren) response bağlaması, response.<fieldName>.<fieldName>.... konumunda kısmi veriler içerir. Bu örnekte response.todoList_insert.id.
mutation CreateTodoListWithFirstItem(
  $listName: String!,
  $itemContent: String!
) @transaction {
  # Step 1
  todoList_insert(data: {
    id_expr: "uuidV4()",
    name: $listName,
  })
  # Step 2:
  todo_insert(data: {
    listId_expr: "response.todoLis<t_insert.id" # -- Grab the newly generated ID from the partial response so far.
    content: $itemContent,
  })
}

this bağlaması

this bağlaması, @check yönergesinin eklendiği alan olarak değerlendirilir. Temel bir durumda, tek değerli sorgu sonuçlarını değerlendirebilirsiniz.

mutation UpdateMovieTitle (
  $movieId: UUID!,
  $newTitle: String!)
  @auth(level: USER)
  @transaction {
  # Step 1: Query and check
  query @redact {
    moviePermission( # Look up a join table called MoviePermission with a compound key.
      key: {movieId: $movieId, userId_expr: "auth.uid"}
    ) {
      # Check if the user has the editor role for the movie. `this` is the string value of `role`.
      # If the parent moviePermission is null, the @check will also fail automatically.
      role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

Döndürülen alan, herhangi bir üst öğe liste olduğu için birden çok kez oluşuyorsa her oluşum, her değere bağlı this ile test edilir.

Belirli bir yolda, bir üst öğe null veya [] ise alana ulaşılamaz ve bu yol için CEL değerlendirmesi atlanır. Başka bir deyişle, değerlendirme yalnızca this null veya null olmayan bir değer olduğunda yapılır ancak hiçbir zaman undefined olduğunda yapılmaz.

Alan kendisi bir liste veya nesne olduğunda this, aşağıdaki örnekte gösterildiği gibi aynı yapıyı (nesneler söz konusu olduğunda seçilen tüm alt öğeler dahil) izler.

mutation UpdateMovieTitle2($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
  # Step 1: Query and check
  query {
    moviePermissions( # Now we query for a list of all matching MoviePermissions.
      where: {movieId: {eq: $movieId}, userId: {eq_expr: "auth.uid"}}
    # This time we execute the @check on the list, so `this` is the list of objects.
    # We can use the `.exists` macro to check if there is at least one matching entry.
    ) @check(expr: "this.exists(p, p.role == 'editor')", message: "You must be an editor of this movie to update title") {
      role
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

Karmaşık ifade söz dizimi

&& ve || operatörleriyle birleştirerek daha karmaşık ifadeler yazabilirsiniz.

mutation UpsertUser($username: String!) @auth(expr: "(auth != n&&ull)  (vars.username == ';joe')")

Aşağıdaki bölümde, kullanılabilen tüm operatörler açıklanmaktadır.

Operatörler ve operatör önceliği

Operatörler ve karşılık gelen öncelikleri için aşağıdaki tabloyu referans olarak kullanın.

Rastgele ifadeler a ve b, bir alan f ve bir dizin i verildiğinde.

Operatör Açıklama Birleşme özelliği
a[i] a() a.f Dizin, arama, alan erişimi soldan sağa
!a -a Tekli olumsuzlama sağdan sola
a/b a%b a*b Çarpma operatörleri soldan sağa
a+b a-b Toplama operatörleri soldan sağa
a>b a>=b a<b a<=b İlişkisel operatörler soldan sağa
a in b Listede veya haritada bulunma soldan sağa
type(a) == t Tür karşılaştırması. Burada t; bool, int, float, number, string, list, map, timestamp veya duration olabilir. soldan sağa
a==b a!=b Karşılaştırma operatörleri soldan sağa
a && b Koşullu VE soldan sağa
a || b Koşullu VEYA soldan sağa
a ? true_value : false_value Üçlü ifade soldan sağa

Kimlik doğrulama jetonlarındaki veriler

auth.token nesnesi aşağıdaki değerleri içerebilir:

Alan Açıklama
email Hesapla ilişkili e-posta adresi (varsa).
email_verified Kullanıcı, email adresine erişimi olduğunu doğruladıysa true. Bazı sağlayıcılar, sahip oldukları e-posta adreslerini otomatik olarak doğrular.
phone_number Hesapla ilişkili telefon numarası (varsa).
name Ayarlanmışsa kullanıcının görünen adı.
sub Kullanıcının Firebase UID'si. Bu, proje içinde benzersizdir.
firebase.identities Bu kullanıcı hesabıyla ilişkili tüm kimliklerin sözlüğü. Sözlüğün anahtarları şunlardan herhangi biri olabilir: email, phone, google.com, facebook.com, github.com, twitter.com. Sözlüğün değerleri, hesapla ilişkili her kimlik sağlayıcı için benzersiz tanımlayıcı dizileridir. Örneğin, auth.token.firebase.identities["google.com"][0], hesapla ilişkili ilk Google kullanıcı kimliğini içerir.
firebase.sign_in_provider Bu jetonu almak için kullanılan oturum açma hizmet sağlayıcısı. Şu dizelerden biri olabilir: custom, password, phone, anonymous, google.com, facebook.com, github.com, twitter.com.
firebase.tenant Hesapla ilişkili tenantId (varsa). Örneğin, tenant2-m6tyz

JWT kimlik jetonlarındaki ek alanlar

Ayrıca aşağıdaki auth.token alanlarına da erişebilirsiniz:

Özel Jeton Talepleri
alg Algoritma "RS256"
iss Düzenleyen Projenizin hizmet hesabı e-posta adresi
sub Konu Projenizin hizmet hesabı e-posta adresi
aud Kitle "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Yayınlanma zamanı UNIX sıfır zamanından itibaren saniye cinsinden geçerli saat
exp Geçerlilik süresi Jetonun geçerliliğinin sona erdiği zaman (UNIX sıfır zamanından itibaren saniye cinsinden). iat tarihinden en fazla 3.600 saniye sonra olabilir.
Not: Bu ayar yalnızca özel jetonun kendisinin sona erme zamanını kontrol eder. Ancak signInWithCustomToken() kullanarak bir kullanıcının oturumunu açtığınızda, oturumu geçersiz kılınana veya kullanıcı oturumu kapatana kadar cihazda oturum açık kalır.
<claims> (isteğe bağlı) İfadelerde auth.token (veya request.auth.token) üzerinden erişilebilen, jetona dahil edilecek isteğe bağlı özel talepler. Örneğin, özel bir talep oluşturursanız adminClaim, auth.token.adminClaim ile bu talebe erişebilirsiniz.

Sırada ne var?