Firebase Data Connect cung cấp khả năng bảo mật mạnh mẽ ở phía máy khách bằng:
- Uỷ quyền ứng dụng dành cho thiết bị di động và web
- Các chế độ kiểm soát uỷ quyền riêng lẻ ở cấp truy vấn và cấp đột biến
- Chứng thực ứng dụng bằng Firebase App Check.
Data Connect mở rộng tính năng bảo mật này bằng:
- Uỷ quyền phía máy chủ
- Bảo mật người dùng dự án Firebase và Cloud SQL bằng IAM.
Uỷ quyền truy vấn và thay đổi của ứng dụng
Data Connect được tích hợp đầy đủ với Firebase Authentication, vì vậy, bạn có thể sử dụng dữ liệu đa dạng thức về những người dùng đang truy cập vào dữ liệu của bạn (xác thực) trong thiết kế của mình để biết những dữ liệu mà những người dùng đó có thể truy cập (uỷ quyền).
Data Connect cung cấp một lệnh @auth
cho các truy vấn và
sự thay đổi cho phép bạn đặt cấp độ xác thực cần thiết để uỷ quyền cho
thao tác. Hướng dẫn này giới thiệu về lệnh @auth
kèm theo ví dụ.
Ngoài ra, Data Connect hỗ trợ việc thực thi các truy vấn được nhúng trong các đột biến, vì vậy, bạn có thể truy xuất các tiêu chí uỷ quyền bổ sung mà bạn đã lưu trữ trong cơ sở dữ liệu và sử dụng các tiêu chí đó trong các lệnh @check
để quyết định xem các đột biến bao gồm có được uỷ quyền hay không. Đối với trường hợp uỷ quyền này, lệnh @redact
cho phép bạn kiểm soát việc kết quả truy vấn có được trả về cho ứng dụng khách trong giao thức truyền tin hay không và truy vấn được nhúng bị bỏ qua trong các SDK được tạo. Tìm phần giới thiệu về các lệnh này, kèm theo ví dụ.
Tìm hiểu về lệnh @auth
Bạn có thể tham số hoá lệnh @auth
để tuân theo một trong nhiều cấp truy cập được đặt trước, bao gồm nhiều trường hợp truy cập phổ biến. Các cấp này dao động từ PUBLIC
(cho phép truy vấn và đột biến từ tất cả ứng dụng khách mà không cần xác thực bất kỳ loại nào) đến NO_ACCESS
(không cho phép truy vấn và đột biến bên ngoài môi trường máy chủ đặc quyền bằng cách sử dụng SDK quản trị Firebase). Mỗi cấp độ này đều tương quan với các luồng xác thực do Firebase Authentication cung cấp.
Cấp độ | Định nghĩa |
---|---|
PUBLIC |
Bất kỳ ai cũng có thể thực thi thao tác này, có hoặc không có xác thực. |
PUBLIC |
Bất kỳ ai cũng có thể thực thi thao tác này, có hoặc không có xác thực. |
USER_ANON |
Mọi người dùng đã xác định, bao gồm cả những người đã đăng nhập ẩn danh bằng Firebase Authentication, đều được phép thực hiện truy vấn hoặc thay đổi. |
USER |
Mọi người dùng đã đăng nhập bằng Firebase Authentication đều được uỷ quyền để thực hiện truy vấn hoặc thay đổi, ngoại trừ người dùng đăng nhập ẩn danh. |
USER_EMAIL_VERIFIED |
Bất kỳ người dùng nào đã đăng nhập bằng Firebase Authentication với địa chỉ email đã xác minh đều được uỷ quyền thực hiện truy vấn hoặc thay đổi. |
NO_ACCESS |
Không thể thực thi thao tác này bên ngoài ngữ cảnh SDK quản trị. |
Bằng cách sử dụng các cấp truy cập đặt trước này làm điểm xuất phát, bạn có thể xác định các bước kiểm tra uỷ quyền phức tạp và mạnh mẽ trong lệnh @auth
bằng cách sử dụng bộ lọc where
và biểu thức Ngôn ngữ biểu thức chung (CEL) được đánh giá trên máy chủ.
Sử dụng lệnh @auth
để triển khai các trường hợp uỷ quyền phổ biến
Các cấp truy cập đặt trước là điểm xuất phát để uỷ quyền.
Cấp truy cập USER
là cấp cơ bản hữu ích nhất để bắt đầu.
Quyền truy cập bảo mật hoàn toàn sẽ được xây dựng dựa trên cấp USER
cùng với các bộ lọc và biểu thức kiểm tra các thuộc tính người dùng, thuộc tính tài nguyên, vai trò và các hoạt động kiểm tra khác. Các cấp độ USER_ANON
và USER_EMAIL_VERIFIED
là các biến thể của trường hợp USER
.
Cú pháp biểu thức cho phép bạn đánh giá dữ liệu bằng cách sử dụng đối tượng auth
đại diện cho dữ liệu xác thực được truyền bằng các thao tác, cả dữ liệu chuẩn trong mã thông báo xác thực và dữ liệu tuỳ chỉnh trong mã thông báo. Để biết danh sách các trường có trong đối tượng auth
, hãy xem phần tham khảo.
Tất nhiên, có những trường hợp sử dụng mà PUBLIC
là cấp truy cập chính xác để bắt đầu. Xin nhắc lại rằng cấp truy cập luôn là điểm xuất phát, đồng thời cần có các bộ lọc và biểu thức bổ sung để tăng cường bảo mật.
Hướng dẫn này hiện đưa ra các ví dụ về cách xây dựng trên USER
và PUBLIC
.
Ví dụ về động lực
Các ví dụ về phương pháp hay nhất sau đây đề cập đến giản đồ sau đây cho một nền tảng viết blog có một số nội dung nhất định bị khoá sau một gói thanh toán.
Nền tảng như vậy có thể mô hình hoá Users
vàPosts
.
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")
}
Tài nguyên thuộc quyền sở hữu của người dùng
Firebase khuyên bạn nên viết các bộ lọc và biểu thức kiểm tra quyền sở hữu tài nguyên của người dùng, trong các trường hợp sau, quyền sở hữu Posts
.
Trong các ví dụ sau, dữ liệu từ mã thông báo xác thực được đọc và so sánh bằng biểu thức. Mẫu thông thường là sử dụng các biểu thức như where: {authorUid:
{eq_expr: "auth.uid"}}
để so sánh authorUid
được lưu trữ với auth.uid
(mã nhận dạng người dùng) được truyền trong mã thông báo xác thực.
Tạo
Phương pháp uỷ quyền này bắt đầu bằng cách thêm auth.uid
từ mã thông báo uỷ quyền vào mỗi Post
mới dưới dạng trường authorUid
để cho phép so sánh trong các kiểm thử uỷ quyền theo trình tự phụ.
# 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
})
}
Cập nhật
Khi một ứng dụng khách tìm cách cập nhật Post
, bạn có thể kiểm thử auth.uid
đã truyền với authorUid
đã lưu trữ.
# 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"
}
)
}
Xóa
Kỹ thuật tương tự cũng được dùng để cho phép các thao tác xoá.
# 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 }
}
Danh sách
# 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
}
}
Lọc dữ liệu
Hệ thống uỷ quyền của Data Connect cho phép bạn ghi các bộ lọc tinh vi kết hợp với các cấp truy cập đặt trước như PUBLIC
cũng như bằng cách sử dụng dữ liệu từ mã thông báo xác thực.
Hệ thống uỷ quyền cũng cho phép bạn chỉ sử dụng biểu thức mà không cần cấp truy cập cơ sở, như trong một số ví dụ sau.
Lọc theo thuộc tính tài nguyên
Ở đây, việc uỷ quyền không dựa trên mã thông báo xác thực vì cấp độ bảo mật cơ sở được đặt thành PUBLIC
. Tuy nhiên, chúng ta có thể thiết lập rõ ràng các bản ghi trong cơ sở dữ liệu là phù hợp để truy cập công khai; giả sử chúng ta có Post
bản ghi trong cơ sở dữ liệu với visibility
được đặt thành "công khai".
# 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
}
}
Lọc theo thông báo xác nhận quyền sở hữu của người dùng
Ở đây, giả sử bạn đã thiết lập các tuyên bố tuỳ chỉnh của người dùng truyền vào mã xác thực để xác định người dùng trong gói "pro" cho ứng dụng của bạn, được gắn cờ bằng trường auth.token.plan
trong mã xác thực. Biểu thức của bạn có thể kiểm tra theo trường này.
# 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
}
}
Lọc theo thứ tự + giới hạn
Hoặc bạn có thể đã đặt visibility
trong các bản ghi Post
để xác định rằng đó là nội dung dành cho người dùng "pro", nhưng đối với bản xem trước hoặc trang thông tin giới thiệu về dữ liệu, hãy giới hạn thêm số lượng bản ghi được trả về.
# 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
}
}
Lọc theo vai trò
Nếu thông báo xác nhận quyền sở hữu tuỳ chỉnh xác định vai trò admin
, bạn có thể kiểm thử và uỷ quyền cho các thao tác tương ứng.
# List all posts unconditionally iff the current user has an admin claim
query AdminListPosts @auth(expr: "auth.token.admin == true") {
posts { ...DisplayPost }
}
Tìm hiểu về lệnh @check
và @redact
Lệnh @check
xác minh rằng các trường đã chỉ định có trong kết quả truy vấn. Biểu thức Ngôn ngữ diễn đạt thông thường (CEL) được dùng để kiểm thử giá trị trường. Hành vi mặc định của lệnh này là kiểm tra và từ chối các nút có giá trị null
.
Chỉ thị @redact
sẽ loại bỏ một phần phản hồi từ ứng dụng. Các trường đã bị loại bỏ vẫn được đánh giá để xem có hiệu ứng phụ nào không (bao gồm cả thay đổi về dữ liệu và @check
) và kết quả vẫn có sẵn cho các bước sau trong biểu thức CEL.
Trong Data Connect, các lệnh @check
và @redact
thường được sử dụng trong ngữ cảnh kiểm tra uỷ quyền; hãy tham khảo phần thảo luận về việc tra cứu dữ liệu uỷ quyền.
Thêm các lệnh @check
và @redact
để tra cứu dữ liệu uỷ quyền
Một trường hợp sử dụng phổ biến của việc uỷ quyền là lưu trữ các vai trò uỷ quyền tuỳ chỉnh trong cơ sở dữ liệu, chẳng hạn như trong bảng quyền đặc biệt và sử dụng các vai trò đó để uỷ quyền cho các đột biến tạo, cập nhật hoặc xoá dữ liệu.
Khi sử dụng tính năng tra cứu dữ liệu uỷ quyền, bạn có thể truy vấn các vai trò dựa trên mã nhận dạng người dùng và sử dụng biểu thức CEL để quyết định xem liệu hành vi thay đổi có được uỷ quyền hay không. Ví dụ: bạn có thể muốn viết một đột biến UpdateMovieTitle
cho phép ứng dụng được uỷ quyền cập nhật tên phim.
Trong phần còn lại của cuộc thảo luận này, giả sử cơ sở dữ liệu ứng dụng đánh giá phim lưu trữ một vai trò uỷ quyền trong bảng 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!
}
Trong ví dụ triển khai sau, đột biến UpdateMovieTitle
bao gồm một trường query
để truy xuất dữ liệu từ MoviePermission
và các lệnh sau để đảm bảo thao tác an toàn và mạnh mẽ:
- Lệnh
@transaction
để đảm bảo tất cả các truy vấn và kiểm tra uỷ quyền đều hoàn tất hoặc không thành công một cách nguyên tử. - Chỉ thị
@redact
để bỏ qua kết quả truy vấn khỏi phản hồi, nghĩa là quy trình kiểm tra uỷ quyền của chúng tôi được thực hiện trên máy chủ Data Connect nhưng dữ liệu nhạy cảm không được hiển thị cho ứng dụng. Một cặp lệnh
@check
để đánh giá logic uỷ quyền trên kết quả truy vấn, chẳng hạn như kiểm thử để đảm bảo rằng một mã nhận dạng người dùng nhất định có vai trò thích hợp để thực hiện các sửa đổi.
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
})
}
Các mẫu đối lập cần tránh trong quá trình uỷ quyền
Phần trước đề cập đến các mẫu cần tuân theo khi sử dụng lệnh @auth
.
Bạn cũng nên lưu ý đến các mẫu đối lập quan trọng cần tránh.
Tránh truyền mã nhận dạng thuộc tính người dùng và tham số mã xác thực trong đối số truy vấn và đột biến
Firebase Authentication là một công cụ mạnh mẽ để trình bày luồng xác thực và ghi lại dữ liệu xác thực một cách an toàn, chẳng hạn như mã nhận dạng người dùng đã đăng ký và nhiều trường được lưu trữ trong mã xác thực.
Bạn không nên truyền mã nhận dạng người dùng và dữ liệu mã thông báo xác thực trong các đối số truy vấn và đột biến.
# 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
}
}
Tránh sử dụng cấp truy cập USER
mà không có bộ lọc nào
Như đã thảo luận nhiều lần trong hướng dẫn, các cấp truy cập cốt lõi như USER
, USER_ANON
, USER_EMAIL_VERIFIED
là đường cơ sở và điểm xuất phát để kiểm tra quyền, được nâng cao bằng các bộ lọc và biểu thức. Việc sử dụng các cấp này mà không có bộ lọc hoặc biểu thức tương ứng để kiểm tra người dùng nào đang thực hiện yêu cầu về cơ bản tương đương với việc sử dụng cấp PUBLIC
.
# Antipattern!
# This incorrectly allows any user to view all documents
query ListDocuments @auth(level: USER) {
documents {
id
title
text
}
}
Tránh sử dụng cấp truy cập PUBLIC
hoặc USER
để tạo bản mô hình
Để đẩy nhanh quá trình phát triển, bạn có thể đặt tất cả các thao tác thành cấp truy cập PUBLIC
hoặc cấp truy cập USER
mà không cần cải tiến thêm để uỷ quyền cho tất cả các thao tác và cho phép bạn nhanh chóng kiểm thử mã.
Khi bạn đã tạo bản nguyên mẫu ban đầu theo cách này, hãy bắt đầu chuyển từ NO_ACCESS
sang cấp độ uỷ quyền sẵn sàng phát hành với các cấp PUBLIC
và USER
.
Tuy nhiên, đừng triển khai các lớp này dưới dạng PUBLIC
hoặc USER
mà không thêm logic bổ sung như trong hướng dẫn này.
# Antipattern!
# This incorrectly allows anyone to delete any post
mutation DeletePost($id: UUID!) @auth(level: PUBLIC) {
post: post_delete(
id: $id,
)
}
Sử dụng Firebase App Check để chứng thực ứng dụng
Xác thực và uỷ quyền là các thành phần quan trọng của tính bảo mật Data Connect. Tính năng xác thực và uỷ quyền kết hợp với tính năng chứng thực ứng dụng tạo nên một giải pháp bảo mật rất mạnh mẽ.
Với tính năng chứng thực thông qua Firebase App Check, các thiết bị chạy ứng dụng của bạn sẽ sử dụng một trình cung cấp chứng thực ứng dụng hoặc thiết bị để chứng thực rằng các hoạt động Data Connect bắt nguồn từ ứng dụng chính thống và các yêu cầu bắt nguồn từ một thiết bị chính thống, không bị can thiệp. Thông tin chứng thực này được đính kèm vào mọi yêu cầu mà ứng dụng của bạn gửi đến Data Connect.
Để tìm hiểu cách bật App Check cho Data Connect và đưa SDK ứng dụng vào ứng dụng, hãy xem thông tin tổng quan về App Check.
Cấp xác thực cho lệnh @auth(level)
Bảng sau đây liệt kê tất cả các cấp truy cập tiêu chuẩn và cấp truy cập tương đương trong CEL. Các cấp xác thực được liệt kê từ rộng đến hẹp – mỗi cấp bao gồm tất cả người dùng khớp với các cấp sau.
Cấp độ | Định nghĩa |
---|---|
PUBLIC |
Bất kỳ ai cũng có thể thực thi thao tác này, có hoặc không có xác thực.
Những điều cần cân nhắc: Mọi người dùng đều có thể đọc hoặc sửa đổi dữ liệu. Firebase đề xuất cấp độ uỷ quyền này cho dữ liệu có thể duyệt công khai như trang thông tin sản phẩm hoặc nội dung nghe nhìn. Xem các ví dụ và phương pháp thay thế hay nhất. Tương đương với @auth(expr: "true")
Không thể sử dụng bộ lọc và biểu thức @auth kết hợp với cấp truy cập này. Mọi biểu thức như vậy sẽ không thành công và báo lỗi yêu cầu xấu 400.
|
USER_ANON |
Mọi người dùng đã xác định, bao gồm cả những người đã đăng nhập ẩn danh bằng Firebase Authentication, đều được phép thực hiện truy vấn hoặc thay đổi.
Lưu ý: USER_ANON là tập hợp lớn hơn của USER .
Những điều cần cân nhắc: Xin lưu ý rằng bạn phải thiết kế cẩn thận các truy vấn và đột biến cho cấp độ uỷ quyền này. Cấp này cho phép người dùng đăng nhập một cách ẩn danh (tự động đăng nhập chỉ liên kết với thiết bị của người dùng) bằng Authentication và không tự thực hiện các bước kiểm tra khác, chẳng hạn như liệu dữ liệu có thuộc về người dùng hay không. Xem các ví dụ và phương pháp thay thế hay nhất. Vì quy trình đăng nhập ẩn danh Authentication phát hành uid , nên cấp USER_ANON tương đương với
@auth(expr: "auth.uid != nil")
|
USER |
Mọi người dùng đã đăng nhập bằng Firebase Authentication đều được uỷ quyền để thực hiện truy vấn hoặc thay đổi, ngoại trừ người dùng đăng nhập ẩn danh.
Những điều cần cân nhắc: Xin lưu ý rằng bạn phải thiết kế cẩn thận các truy vấn và đột biến cho cấp độ uỷ quyền này. Cấp này chỉ kiểm tra xem người dùng đã đăng nhập bằng Authentication hay chưa và không tự thực hiện các bước kiểm tra khác, chẳng hạn như liệu dữ liệu có thuộc về người dùng hay không. Xem các ví dụ và phương pháp thay thế hay nhất. Tương đương với @auth(expr: "auth.uid != nil &&
auth.token.firebase.sign_in_provider != 'anonymous'")"
|
USER_EMAIL_VERIFIED |
Bất kỳ người dùng nào đã đăng nhập bằng Firebase Authentication với địa chỉ email đã xác minh đều được uỷ quyền thực hiện truy vấn hoặc thay đổi.
Những điều cần cân nhắc: Vì quy trình xác minh email được thực hiện bằng Authentication, nên quy trình này dựa trên phương thức Authentication mạnh mẽ hơn, do đó, cấp độ này mang lại thêm tính bảo mật so với USER hoặc USER_ANON . Cấp này chỉ kiểm tra để đảm bảo rằng người dùng đã đăng nhập bằng Authentication bằng email đã xác minh và không tự thực hiện các bước kiểm tra khác, chẳng hạn như liệu dữ liệu có thuộc về người dùng hay không. Xem các ví dụ và phương pháp thay thế hay nhất.
Tương đương với @auth(expr: "auth.uid != nil &&
auth.token.email_verified")" |
NO_ACCESS |
Không thể thực thi thao tác này bên ngoài ngữ cảnh SDK quản trị.
Tương đương với @auth(expr: "false") |
Tài liệu tham khảo CEL cho @auth(expr)
và @check(expr)
Như trong các ví dụ khác trong hướng dẫn này, bạn có thể và nên sử dụng các biểu thức được xác định trong Ngôn ngữ biểu thức chung (CEL) để kiểm soát quyền cho Data Connect bằng các lệnh @auth(expr:)
và @check
.
Phần này trình bày cú pháp CEL liên quan đến việc tạo biểu thức cho các lệnh này.
Thông tin tham khảo đầy đủ về CEL được cung cấp trong quy cách CEL.
Kiểm thử các biến được truyền trong truy vấn và đột biến
Cú pháp @auth(expr)
cho phép bạn truy cập và kiểm thử các biến từ truy vấn và
sự thay đổi.
Ví dụ: bạn có thể đưa một biến toán tử, chẳng hạn như $status
, vào bằng cách sử dụng vars.status
.
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
Dữ liệu có sẵn cho biểu thức
Cả biểu thức CEL @auth(expr:)
và @check(expr:)
đều có thể đánh giá các giá trị sau:
request.operationName
vars
(bí danh củarequest.variables
)auth
(bí danh củarequest.auth
)
Ngoài ra, biểu thức @check(expr:)
có thể đánh giá:
this
(giá trị của trường hiện tại)
Đối tượng request.operationName
Đối tượng request.operarationName
lưu trữ loại toán tử, truy vấn hoặc đột biến.
Đối tượng vars
Đối tượng vars
cho phép biểu thức của bạn truy cập vào tất cả các biến được truyền trong truy vấn hoặc đột biến.
Bạn có thể sử dụng vars.<variablename>
trong một biểu thức làm bí danh cho request.variables.<variablename>
đủ điều kiện:
# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")
Đối tượng auth
Authentication xác định những người dùng yêu cầu quyền truy cập vào dữ liệu của bạn và cung cấp thông tin đó dưới dạng một đối tượng mà bạn có thể xây dựng trong biểu thức.
Trong bộ lọc và biểu thức, bạn có thể sử dụng auth
làm bí danh cho request.auth
.
Đối tượng auth chứa các thông tin sau:
uid
: Mã nhận dạng người dùng duy nhất, được chỉ định cho người dùng yêu cầu.token
: Bản đồ các giá trị do Authentication thu thập.
Để biết thêm thông tin chi tiết về nội dung của auth.token
, hãy xem phần Dữ liệu trong mã thông báo xác thực
Liên kết this
this
liên kết sẽ đánh giá thành trường mà lệnh @check
được đính kèm. Trong trường hợp cơ bản, bạn có thể đánh giá kết quả truy vấn có giá trị đơn.
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
})
}
Nếu trường được trả về xuất hiện nhiều lần vì bất kỳ thành phần mẹ nào cũng là một danh sách, thì mỗi lần xuất hiện sẽ được kiểm thử bằng this
liên kết với từng giá trị.
Đối với bất kỳ đường dẫn nào, nếu một thành phần cấp trên là null
hoặc []
, thì trường đó sẽ không được truy cập và quá trình đánh giá CEL sẽ bị bỏ qua đối với đường dẫn đó. Nói cách khác, quá trình đánh giá chỉ diễn ra khi this
là null
hoặc không phải null
, nhưng không bao giờ là undefined
.
Khi chính trường là một danh sách hoặc đối tượng, this
sẽ tuân theo cùng một cấu trúc (bao gồm tất cả các phần tử con được chọn trong trường hợp đối tượng), như minh hoạ trong ví dụ sau.
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
})
}
Cú pháp biểu thức phức tạp
Bạn có thể viết biểu thức phức tạp hơn bằng cách kết hợp với toán tử &&
và ||
.
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
Phần sau đây mô tả tất cả toán tử có sẵn.
Toán tử và thứ tự ưu tiên của toán tử
Hãy sử dụng bảng sau đây để tham khảo các toán tử và thứ tự ưu tiên tương ứng.
Cho biểu thức tuỳ ý a
và b
, một trường f
và một chỉ mục i
.
Toán tử | Mô tả | Tính liên kết |
---|---|---|
a[i] a() a.f |
Chỉ mục, lệnh gọi, quyền truy cập vào trường | từ trái sang phải |
!a -a |
Phủ định một ngôi | phải sang trái |
a/b a%b a*b |
Toán tử nhân | từ trái sang phải |
a+b a-b |
Toán tử cộng | từ trái sang phải |
a>b a>=b a<b a<=b |
Toán tử quy chiếu | từ trái sang phải |
a in b |
Sự tồn tại trong danh sách hoặc bản đồ | từ trái sang phải |
type(a) == t |
So sánh kiểu, trong đó t có thể là bool, int, float, số, chuỗi, danh sách, bản đồ, dấu thời gian hoặc thời lượng |
từ trái sang phải |
a==b a!=b |
Toán tử so sánh | từ trái sang phải |
a && b |
AND có điều kiện | từ trái sang phải |
a || b |
Toán tử HOẶC có điều kiện | từ trái sang phải |
a ? true_value : false_value |
Biểu thức ba ngôi | từ trái sang phải |
Dữ liệu trong mã thông báo xác thực
Đối tượng auth.token
có thể chứa các giá trị sau:
Trường | Mô tả |
---|---|
email |
Địa chỉ email liên kết với tài khoản, nếu có. |
email_verified |
true nếu người dùng đã xác minh rằng họ có quyền truy cập vào địa chỉ email . Một số nhà cung cấp tự động xác minh địa chỉ email mà họ sở hữu. |
phone_number |
Số điện thoại được liên kết với tài khoản (nếu có). |
name |
Tên hiển thị của người dùng, nếu được đặt. |
sub |
UID Firebase của người dùng. Đây là giá trị duy nhất trong một dự án. |
firebase.identities |
Từ điển của tất cả danh tính được liên kết với tài khoản của người dùng này. Các khoá của từ điển có thể là bất kỳ khoá nào sau đây: email , phone , google.com , facebook.com , github.com , twitter.com . Các giá trị của từ điển là các mảng gồm giá trị nhận dạng duy nhất cho từng nhà cung cấp danh tính được liên kết với tài khoản. Ví dụ: auth.token.firebase.identities["google.com"][0] chứa mã nhận dạng người dùng Google đầu tiên được liên kết với tài khoản. |
firebase.sign_in_provider |
Nhà cung cấp dịch vụ đăng nhập dùng để lấy mã thông báo này. Có thể là một trong các chuỗi sau: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com . |
firebase.tenant |
tenantId được liên kết với tài khoản, nếu có. Ví dụ: tenant2-m6tyz |
Các trường bổ sung trong mã thông báo nhận dạng JWT
Bạn cũng có thể truy cập vào các trường auth.token
sau:
Xác nhận quyền sở hữu mã thông báo tuỳ chỉnh | ||
---|---|---|
alg |
Thuật toán | "RS256" |
iss |
Tổ chức phát hành | Địa chỉ email của tài khoản dịch vụ của dự án |
sub |
Chủ đề | Địa chỉ email của tài khoản dịch vụ của dự án |
aud |
Đối tượng | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Thời gian phát hành | Thời gian hiện tại, tính bằng giây kể từ thời gian bắt đầu của hệ thống UNIX |
exp |
Thời gian hết hạn |
Thời gian (tính bằng giây kể từ thời gian bắt đầu của hệ thống UNIX) mà mã thông báo hết hạn. Thời gian này có thể muộn tối đa 3600 giây so với iat .
Lưu ý: điều này chỉ kiểm soát thời điểm mã thông báo tuỳ chỉnh hết hạn. Tuy nhiên, sau khi bạn đăng nhập cho người dùng bằng signInWithCustomToken() , họ sẽ vẫn duy trì trạng thái đăng nhập vào thiết bị cho đến khi phiên của họ không hợp lệ hoặc người dùng đăng xuất.
|
<claims> (không bắt buộc) |
Các thông báo xác nhận quyền sở hữu tuỳ chỉnh không bắt buộc để đưa vào mã thông báo. Bạn có thể truy cập thông báo xác nhận quyền sở hữu này thông qua auth.token (hoặc request.auth.token ) trong biểu thức. Ví dụ: nếu tạo một đơn khiếu nại tuỳ chỉnh adminClaim , bạn có thể truy cập vào đơn khiếu nại đó bằng auth.token.adminClaim .
|
Tiếp theo là gì?
- Firebase Data Connect cung cấp một SDK dành cho quản trị viên để cho phép bạn thực hiện các truy vấn và đột biến từ các môi trường đặc quyền.
- Tìm hiểu về tính năng bảo mật IAM trong hướng dẫn quản lý dịch vụ và cơ sở dữ liệu.