Menghubungkan Data Aman dengan otorisasi dan pengesahan

Firebase Data Connect memberikan keamanan sisi klien yang andal dengan:

  • Otorisasi klien seluler dan web
  • Kontrol otorisasi tingkat kueri dan mutasi individual
  • Pengesahan aplikasi dengan Firebase App Check.

Data Connect memperluas keamanan ini dengan:

  • Otorisasi sisi server
  • Keamanan pengguna project Firebase dan Cloud SQL dengan IAM.

Memberi otorisasi kueri dan mutasi klien

Data Connect terintegrasi sepenuhnya dengan Firebase Authentication, sehingga Anda dapat menggunakan data lengkap tentang pengguna yang mengakses data Anda (autentikasi) dalam desain untuk data yang dapat diakses pengguna tersebut (otorisasi).

Data Connect menyediakan perintah @auth untuk kueri dan mutasi yang memungkinkan Anda menetapkan tingkat autentikasi yang diperlukan untuk memberikan otorisasi pada operasi. Panduan ini memperkenalkan perintah @auth, dengan contoh.

Selain itu, Data Connect mendukung eksekusi kueri yang disematkan dalam mutasi, sehingga Anda dapat mengambil kriteria otorisasi tambahan yang telah disimpan dalam database, dan menggunakan kriteria tersebut dalam perintah @check untuk memutuskan apakah mutasi yang menyertainya diotorisasi. Untuk kasus otorisasi ini, perintah @redact memungkinkan Anda mengontrol apakah hasil kueri ditampilkan kepada klien dalam protokol wire dan kueri tersemat dihilangkan dalam SDK yang dihasilkan. Temukan pengantar perintah ini, beserta contohnya.

Memahami perintah @auth

Anda dapat membuat parameter perintah @auth untuk mengikuti salah satu dari beberapa tingkat akses preset yang mencakup banyak skenario akses umum. Tingkat ini berkisar dari PUBLIC (yang mengizinkan kueri dan mutasi dari semua klien tanpa autentikasi apa pun) hingga NO_ACCESS (yang tidak mengizinkan kueri dan mutasi di luar lingkungan server dengan hak istimewa menggunakan Firebase Admin SDK). Setiap level ini berkorelasi dengan alur autentikasi yang disediakan oleh Firebase Authentication.

Tingkat Definisi
PUBLIC Operasi ini dapat dijalankan oleh siapa saja dengan atau tanpa autentikasi.
PUBLIC Operasi ini dapat dijalankan oleh siapa saja dengan atau tanpa autentikasi.
USER_ANON Setiap pengguna yang diidentifikasi, termasuk pengguna yang telah login secara anonim dengan Firebase Authentication, diberi otorisasi untuk menjalankan kueri atau mutasi.
USER Setiap pengguna yang telah login dengan Firebase Authentication diberi otorisasi untuk menjalankan kueri atau mutasi, kecuali pengguna login anonim.
USER_EMAIL_VERIFIED Setiap pengguna yang telah login dengan Firebase Authentication dengan alamat email yang terverifikasi diberi otorisasi untuk melakukan kueri atau mutasi.
NO_ACCESS Operasi ini tidak dapat dijalankan di luar konteks Admin SDK.

Dengan menggunakan tingkat akses preset ini sebagai titik awal, Anda dapat menentukan pemeriksaan otorisasi yang kompleks dan andal dalam perintah @auth menggunakan filter where dan ekspresi Common Expression Language (CEL) yang dievaluasi di server.

Menggunakan perintah @auth untuk menerapkan skenario otorisasi umum

Tingkat akses preset adalah titik awal untuk otorisasi.

Tingkat akses USER adalah tingkat dasar yang paling berguna untuk memulai.

Akses yang sepenuhnya aman akan dibuat di tingkat USER beserta filter dan ekspresi yang memeriksa atribut pengguna, atribut resource, peran, dan pemeriksaan lainnya. Level USER_ANON dan USER_EMAIL_VERIFIED adalah variasi pada kasus USER.

Sintaksis ekspresi memungkinkan Anda mengevaluasi data menggunakan objek auth yang mewakili data autentikasi yang diteruskan dengan operasi, baik data standar dalam token autentikasi maupun data kustom dalam token. Untuk mengetahui daftar kolom yang tersedia di objek auth, lihat bagian referensi.

Tentu saja ada kasus penggunaan saat PUBLIC adalah tingkat akses yang benar untuk dimulai. Sekali lagi, tingkat akses selalu menjadi titik awal, dan filter serta ekspresi tambahan diperlukan untuk keamanan yang andal.

Panduan ini sekarang memberikan contoh cara mem-build di USER dan PUBLIC.

Contoh motivasi

Contoh praktik terbaik berikut merujuk pada skema berikut untuk platform blog dengan konten tertentu yang dikunci di balik paket pembayaran.

Platform semacam itu kemungkinan akan membuat model Users danPosts.

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")
}

Resource milik pengguna

Firebase merekomendasikan agar Anda menulis filter dan ekspresi yang menguji kepemilikan pengguna atas resource, dalam kasus berikut, kepemilikan Posts.

Dalam contoh berikut, data dari token autentikasi dibaca dan dibandingkan menggunakan ekspresi. Pola umumnya adalah menggunakan ekspresi seperti where: {authorUid: {eq_expr: "auth.uid"}} untuk membandingkan authorUid yang disimpan dengan auth.uid (ID pengguna) yang diteruskan dalam token autentikasi.

Buat

Praktik otorisasi ini dimulai dengan menambahkan auth.uid dari token autentikasi ke setiap Post baru sebagai kolom authorUid untuk memungkinkan perbandingan dalam pengujian otorisasi urutan berikutnya.

# 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
  })
}
Perbarui

Saat klien mencoba mengupdate Post, Anda dapat menguji auth.uid yang diteruskan dengan authorUid yang disimpan.

# 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"
    }
  )
}
Hapus

Teknik yang sama digunakan untuk memberikan otorisasi operasi penghapusan.

# 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 }
}
Daftar
# 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
  }
}
Dapatkan
# 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
  }
}

Memfilter Data

Sistem otorisasi Data Connect memungkinkan Anda menulis filter yang canggih yang digabungkan dengan tingkat akses preset seperti PUBLIC serta dengan menggunakan data dari token autentikasi.

Sistem otorisasi juga memungkinkan Anda menggunakan ekspresi saja, tanpa tingkat akses dasar, seperti yang ditunjukkan dalam beberapa contoh berikut.

Memfilter menurut atribut resource

Di sini, otorisasi tidak didasarkan pada token autentikasi karena tingkat keamanan dasar ditetapkan ke PUBLIC. Namun, kita dapat menetapkan data di database secara eksplisit sebagai cocok untuk akses publik; asumsikan kita memiliki data Post di database dengan visibility ditetapkan ke "public".

# 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
  }
}
Memfilter menurut klaim pengguna

Di sini, asumsikan Anda telah menyiapkan klaim pengguna kustom yang meneruskan token autentikasi untuk mengidentifikasi pengguna dalam paket "pro" untuk aplikasi Anda, yang ditandai dengan kolom auth.token.plan di token autentikasi. Ekspresi Anda dapat diuji terhadap kolom ini.

# 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
  }
}
Filter menurut urutan + batas

Atau lagi, Anda mungkin telah menetapkan visibility dalam data Post untuk mengidentifikasi bahwa data tersebut adalah konten yang tersedia untuk pengguna "pro", tetapi untuk pratinjau atau listingan teaser data, batasi lebih lanjut jumlah data yang ditampilkan.

# 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
  }
}
Memfilter menurut peran

Jika klaim kustom menentukan peran admin, Anda dapat menguji dan memberikan otorisasi pada operasi yang sesuai.

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

Memahami perintah @check dan @redact

Perintah @check memverifikasi bahwa kolom yang ditentukan ada dalam hasil kueri. Ekspresi Common Expression Language (CEL) digunakan untuk menguji nilai kolom. Perilaku default perintah ini adalah memeriksa dan menolak node bernilai null.

Perintah @redact menyamarkan bagian respons dari klien. Kolom yang disamarkan masih dievaluasi untuk efek samping (termasuk perubahan data dan @check) dan hasilnya masih tersedia untuk langkah berikutnya dalam ekspresi CEL.

Di Data Connect, perintah @check dan @redact paling sering digunakan dalam konteks pemeriksaan otorisasi; lihat diskusi pencarian data otorisasi.

Menambahkan perintah @check dan @redact untuk mencari data otorisasi

Kasus penggunaan otorisasi umum melibatkan penyimpanan peran otorisasi kustom di database Anda, misalnya dalam tabel izin khusus, dan menggunakan peran tersebut untuk memberikan otorisasi mutasi guna membuat, memperbarui, atau menghapus data.

Dengan menggunakan pencarian data otorisasi, Anda dapat membuat kueri untuk peran berdasarkan userID dan menggunakan ekspresi CEL untuk memutuskan apakah mutasi diotorisasi. Misalnya, Anda mungkin ingin menulis mutasi UpdateMovieTitle yang memungkinkan klien yang diotorisasi memperbarui judul film.

Untuk sisa diskusi ini, asumsikan database aplikasi ulasan film menyimpan peran otorisasi dalam tabel MoviePermission.

# MoviePermission
# Suppose a user has an authorization role with respect to records in the Movie table
type MoviePermission @table(key: ["doc", "userId"]) {
  movie: Movie! # implies another field: movieId: UUID!
  userId: String! # Can also be a reference to a User table, doesn't matter
  role: String!
}

Dalam contoh implementasi berikut, mutasi UpdateMovieTitle menyertakan kolom query untuk mengambil data dari MoviePermission, dan perintah berikut untuk memastikan operasi aman dan andal:

  • Perintah @transaction untuk memastikan semua kueri dan pemeriksaan otorisasi selesai atau gagal secara atomik.
  • Perintah @redact untuk menghapus hasil kueri dari respons, yang berarti pemeriksaan otorisasi kami dilakukan di server Data Connect, tetapi data sensitif tidak ditampilkan kepada klien.
  • Sepasang perintah @check untuk mengevaluasi logika otorisasi pada hasil kueri, seperti menguji apakah userID tertentu memiliki peran yang sesuai untuk melakukan perubahan.

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
  })
}

Antipola yang harus dihindari dalam otorisasi

Bagian sebelumnya membahas pola yang harus diikuti saat menggunakan perintah @auth.

Anda juga harus mengetahui antipola penting yang harus dihindari.

Hindari meneruskan ID atribut pengguna dan parameter token autentikasi dalam argumen kueri dan mutasi

Firebase Authentication adalah alat yang canggih untuk menampilkan alur autentikasi dan mengambil data autentikasi dengan aman seperti ID pengguna terdaftar dan banyak kolom yang disimpan dalam token autentikasi.

Sebaiknya jangan meneruskan ID pengguna dan data token autentikasi dalam argumen kueri dan mutasi.

# 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
  }
}

Hindari penggunaan tingkat akses USER tanpa filter

Seperti yang telah dibahas beberapa kali dalam panduan ini, tingkat akses inti seperti USER, USER_ANON, USER_EMAIL_VERIFIED adalah dasar pengukuran dan titik awal untuk pemeriksaan otorisasi, yang akan ditingkatkan dengan filter dan ekspresi. Menggunakan level ini tanpa filter atau ekspresi yang sesuai yang memeriksa pengguna yang melakukan permintaan pada dasarnya setara dengan menggunakan level PUBLIC.

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

Menghindari penggunaan tingkat akses PUBLIC atau USER untuk pembuatan prototipe

Untuk mempercepat pengembangan, Anda mungkin ingin menetapkan semua operasi ke level akses PUBLIC atau ke level akses USER tanpa peningkatan lebih lanjut untuk memberi otorisasi semua operasi dan memungkinkan Anda menguji kode dengan cepat.

Setelah Anda melakukan pembuatan prototipe awal dengan cara ini, mulai beralih dari NO_ACCESS ke otorisasi siap produksi dengan level PUBLIC dan USER. Namun, jangan deploynya sebagai PUBLIC atau USER tanpa menambahkan logika tambahan seperti yang ditunjukkan dalam panduan ini.

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

Menggunakan Firebase App Check untuk pengesahan aplikasi

Autentikasi dan otorisasi adalah komponen penting dari keamanan Data Connect. Autentikasi dan otorisasi yang dikombinasikan dengan atestasi aplikasi akan menghasilkan solusi keamanan yang sangat andal.

Dengan pengesahan melalui Firebase App Check, perangkat yang menjalankan aplikasi Anda akan menggunakan penyedia pengesahan aplikasi atau perangkat yang menyatakan bahwa operasi Data Connect berasal dari aplikasi asli Anda dan permintaan berasal dari perangkat asli yang tidak dimodifikasi. Pengesahan ini dilampirkan ke setiap permintaan yang dibuat aplikasi Anda ke Data Connect.

Untuk mempelajari cara mengaktifkan App Check untuk Data Connect dan menyertakan SDK kliennya di aplikasi Anda, lihat ringkasan App Check.

Tingkat autentikasi untuk perintah @auth(level)

Tabel berikut mencantumkan semua tingkat akses standar dan CEL yang setara. Tingkat autentikasi dicantumkan dari yang luas ke yang sempit -- setiap tingkat mencakup semua pengguna yang cocok dengan tingkat berikut.

Tingkat Definisi
PUBLIC Operasi ini dapat dijalankan oleh siapa saja dengan atau tanpa autentikasi.

Pertimbangan: Data dapat dibaca atau diubah oleh pengguna mana pun. Firebase merekomendasikan tingkat otorisasi ini untuk data yang dapat dijelajahi secara publik seperti listingan produk atau media. Lihat contoh dan alternatif praktik terbaik.

Setara dengan filter dan ekspresi @auth(expr: "true")

@auth tidak dapat digunakan bersama dengan tingkat akses ini. Ekspresi tersebut akan gagal dengan error permintaan buruk 400.
USER_ANON Setiap pengguna yang diidentifikasi, termasuk pengguna yang telah login secara anonim dengan Firebase Authentication, diberi otorisasi untuk menjalankan kueri atau mutasi.

Catatan: USER_ANON adalah superset dari USER.

Pertimbangan: Perhatikan bahwa Anda harus mendesain kueri dan mutasi dengan cermat untuk tingkat otorisasi ini. Tingkat ini memungkinkan pengguna login secara anonim (login otomatis yang hanya terikat dengan perangkat pengguna) dengan Authentication, dan tidak melakukan pemeriksaan lain secara mandiri, misalnya, apakah data milik pengguna. Lihat contoh dan alternatif praktik terbaik.

Karena alur login anonim Authentication menerbitkan uid, level USER_ANON setara dengan
@auth(expr: "auth.uid != nil")
USER Setiap pengguna yang telah login dengan Firebase Authentication diberi otorisasi untuk menjalankan kueri atau mutasi, kecuali pengguna login anonim.

Pertimbangan: Perhatikan bahwa Anda harus mendesain kueri dan mutasi dengan cermat untuk tingkat otorisasi ini. Tingkat ini hanya memeriksa apakah pengguna login dengan Authentication, dan tidak secara mandiri melakukan pemeriksaan lain, misalnya, apakah data milik pengguna. Lihat contoh dan alternatif praktik terbaik.

Setara dengan @auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")"
USER_EMAIL_VERIFIED Setiap pengguna yang telah login dengan Firebase Authentication dengan alamat email yang terverifikasi diberi otorisasi untuk melakukan kueri atau mutasi.

Pertimbangan: Karena verifikasi email dilakukan menggunakan Authentication, verifikasi ini didasarkan pada metode Authentication yang lebih andal, sehingga tingkat ini memberikan keamanan tambahan dibandingkan dengan USER atau USER_ANON. Tingkat ini hanya memeriksa apakah pengguna login dengan Authentication menggunakan email terverifikasi, dan tidak melakukan pemeriksaan lain secara mandiri, misalnya, apakah data milik pengguna. Lihat contoh dan alternatif praktik terbaik.

Setara dengan @auth(expr: "auth.uid != nil && auth.token.email_verified")"
NO_ACCESS Operasi ini tidak dapat dijalankan di luar konteks Admin SDK.

Setara dengan @auth(expr: "false")

Referensi CEL untuk @auth(expr) dan @check(expr)

Seperti yang ditunjukkan dalam contoh di tempat lain dalam panduan ini, Anda dapat dan harus menggunakan ekspresi yang ditentukan dalam Common Expression Language (CEL) untuk mengontrol otorisasi untuk Data Connect menggunakan perintah @auth(expr:) dan @check.

Bagian ini membahas sintaksis CEL yang relevan dengan pembuatan ekspresi untuk perintah ini.

Informasi referensi lengkap untuk CEL disediakan dalam spesifikasi CEL.

Menguji variabel yang diteruskan dalam kueri dan mutasi

Sintaksis @auth(expr) memungkinkan Anda mengakses dan menguji variabel dari kueri dan mutasi.

Misalnya, Anda dapat menyertakan variabel operasi, seperti $status, menggunakan vars.status.

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

Data yang tersedia untuk ekspresi

Ekspresi CEL @auth(expr:) dan @check(expr:) dapat mengevaluasi hal berikut:

  • request.operationName
  • vars (alias untuk request.variables)
  • auth (alias untuk request.auth)

Selain itu, ekspresi @check(expr:) dapat mengevaluasi:

  • this (nilai kolom saat ini)

Objek request.operationName

Objek request.operarationName menyimpan jenis operasi, baik kueri maupun mutasi.

Objek vars

Objek vars memungkinkan ekspresi Anda mengakses semua variabel yang diteruskan dalam kueri atau mutasi.

Anda dapat menggunakan vars.<variablename> dalam ekspresi sebagai alias untuk request.variables.<variablename> yang sepenuhnya memenuhi syarat:

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

Objek auth

Authentication mengidentifikasi pengguna yang meminta akses ke data Anda dan memberikan informasi tersebut sebagai objek yang dapat Anda buat dalam ekspresi.

Dalam filter dan ekspresi, Anda dapat menggunakan auth sebagai alias untuk request.auth.

Objek auth berisi informasi berikut:

  • uid: ID pengguna unik, yang ditetapkan untuk pengguna yang meminta.
  • token: Peta nilai yang dikumpulkan oleh Authentication.

Untuk mengetahui detail selengkapnya tentang konten auth.token, lihat Data dalam token autentikasi

Binding this

this pengikatan dievaluasi ke kolom tempat perintah @check disertakan. Dalam kasus dasar, Anda dapat mengevaluasi hasil kueri bernilai tunggal.

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
  })
}

Jika kolom yang ditampilkan muncul beberapa kali karena setiap ancestor adalah daftar, setiap kejadian akan diuji dengan this yang terikat ke setiap nilai.

Untuk jalur tertentu, jika ancestor adalah null atau [], kolom tidak akan dijangkau dan evaluasi CEL akan dilewati untuk jalur tersebut. Dengan kata lain, evaluasi hanya terjadi jika this adalah null atau non-null, tetapi tidak pernah undefined.

Jika kolom itu sendiri adalah daftar atau objek, this akan mengikuti struktur yang sama (termasuk semua turunan yang dipilih jika berupa objek), seperti yang diilustrasikan dalam contoh berikut.

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
  })
}

Sintaksis ekspresi kompleks

Anda dapat menulis ekspresi yang lebih kompleks dengan menggabungkannya dengan operator && dan ||.

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

Bagian berikut menjelaskan semua operator yang tersedia.

Operator dan prioritas operator

Gunakan tabel berikut sebagai referensi untuk operator dan prioritasnya yang sesuai.

Ekspresi arbitrer tertentu a dan b, kolom f, dan indeks i.

Operator Deskripsi Asosiativitas
a[i] a() a.f Akses indeks, panggilan, kolom kiri ke kanan
!a -a Negasi unary kanan ke kiri
a/b a%b a*b Operator multiplikatif kiri ke kanan
a+b a-b Operator aditif kiri ke kanan
a>b a>=b a<b a<=b Operator relasional kiri ke kanan
a in b Keberadaan dalam daftar atau peta kiri ke kanan
type(a) == t Perbandingan jenis, dengan t dapat berupa bool, int, float, angka, string, daftar, peta, stempel waktu, atau durasi kiri ke kanan
a==b a!=b Operator perbandingan kiri ke kanan
a && b AND kondisional kiri ke kanan
a || b OR kondisional kiri ke kanan
a ? true_value : false_value Ekspresi ternary kiri ke kanan

Data dalam token autentikasi

Objek auth.token dapat berisi nilai berikut:

Kolom Deskripsi
email Alamat email yang terhubung dengan akun, jika ada.
email_verified true jika pengguna telah memverifikasi bahwa mereka memiliki akses ke alamat email. Beberapa penyedia secara otomatis memverifikasi alamat email yang mereka miliki.
phone_number Nomor telepon yang terkait dengan akun, jika ada.
name Nama tampilan pengguna, jika ditetapkan.
sub UID Firebase pengguna. UID ini bersifat unik dalam sebuah project.
firebase.identities Kamus yang memuat semua identitas terkait akun pengguna ini. Kunci kamus dapat berupa salah satu dari berikut ini: email, phone, google.com, facebook.com, github.com, twitter.com. Nilai kamus adalah array ID unik untuk setiap penyedia identitas yang terkait dengan akun. Misalnya, auth.token.firebase.identities["google.com"][0] berisi ID pengguna Google pertama yang dikaitkan dengan akun.
firebase.sign_in_provider Penyedia login yang digunakan untuk mendapatkan token ini. Dapat berupa salah satu string berikut: custom, password, phone, anonymous, google.com, facebook.com, github.com, twitter.com.
firebase.tenant tenantId yang terkait dengan akun, jika ada. Contoh, tenant2-m6tyz

Kolom tambahan di token ID JWT

Anda juga dapat mengakses kolom auth.token berikut:

Klaim Token Kustom
alg Algoritme "RS256"
iss Penerbit Alamat email akun layanan project Anda
sub Subjek Alamat email akun layanan project Anda
aud Audience "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Waktu penerbitan Waktu saat ini, dalam satuan detik sejak epoch UNIX
exp Waktu habis masa berlaku Waktu saat token sudah tidak berlaku lagi, dalam satuan detik sejak epoch UNIX. Waktu ini bisa mencapai maksimum 3600 detik lebih lama daripada iat.
Catatan: ini hanya mengontrol kapan token kustom berhenti berlaku. Namun, setelah Anda memproses login menggunakan signInWithCustomToken(), pengguna akan tetap login di perangkatnya hingga validitas sesi berakhir atau pengguna tersebut logout.
<claims> (opsional) Klaim kustom opsional yang akan disertakan dalam token, yang dapat diakses melalui auth.token (atau request.auth.token) dalam ekspresi. Misalnya, jika Anda membuat adminClaim klaim kustom, Anda dapat mengaksesnya dengan auth.token.adminClaim.

Apa langkah selanjutnya?