Firebase Data Connect는 다음과 같은 강력한 클라이언트 측 보안을 제공합니다.
- 모바일 및 웹 클라이언트 승인
- 개별 쿼리 및 변형 수준 승인 제어
- Firebase App Check를 통한 앱 증명
Data Connect는 다음과 같이 이 보안을 확장합니다.
- 서버 측 승인
- IAM을 사용한 Firebase 프로젝트 및 Cloud SQL 사용자 보안
클라이언트 쿼리 및 변형 승인
Data Connect는 Firebase Authentication와 완전히 통합되어 있으므로 설계에서 데이터에 액세스하는 사용자 (인증)에 관한 풍부한 데이터를 사용하여 사용자가 액세스할 수 있는 데이터 (승인)를 지정할 수 있습니다.
Data Connect는 쿼리 및 변형에 @auth
디렉티브를 제공하여 작업을 승인하는 데 필요한 인증 수준을 설정할 수 있습니다. 이 가이드에서는 예시를 통해 @auth
지시문을 소개합니다.
또한 Data Connect는 변형에 삽입된 쿼리의 실행을 지원하므로 데이터베이스에 저장한 추가 승인 기준을 검색하고 @check
디렉티브에서 이러한 기준을 사용하여 괄호로 묶인 변형이 승인되었는지 결정할 수 있습니다. 이 승인 사례의 경우 @redact
지시어를 사용하면 쿼리 결과가 전송 프로토콜에서 클라이언트에게 반환되는지 여부와 생성된 SDK에서 생략된 삽입된 쿼리를 제어할 수 있습니다. 예시가 포함된 이러한 지시문 소개를 확인하세요.
@auth
지시문 이해
@auth
디렉티브를 매개변수화하여 여러 일반적인 액세스 시나리오를 다루는 여러 사전 설정된 액세스 수준 중 하나를 따를 수 있습니다. 이러한 수준은 PUBLIC
(어떠한 종류의 인증도 없이 모든 클라이언트의 쿼리 및 변형을 허용함)에서 NO_ACCESS
(Firebase Admin SDK를 사용하는 권한이 있는 서버 환경 외부의 쿼리 및 변형을 허용하지 않음)까지 다양합니다. 이러한 각 수준은 Firebase Authentication에서 제공하는 인증 흐름과 연관됩니다.
수준 | 정의 |
---|---|
PUBLIC |
이 작업은 인증 여부와 관계없이 누구나 실행할 수 있습니다. |
PUBLIC |
이 작업은 인증 여부와 관계없이 누구나 실행할 수 있습니다. |
USER_ANON |
Firebase Authentication로 익명으로 로그인한 사용자를 포함하여 식별된 모든 사용자는 쿼리 또는 변형을 실행할 권한이 있습니다. |
USER |
Firebase Authentication로 로그인한 모든 사용자는 익명 로그인 사용자를 제외하고 쿼리 또는 변형을 실행할 권한이 있습니다. |
USER_EMAIL_VERIFIED |
인증된 이메일 주소로 Firebase Authentication로 로그인한 모든 사용자는 쿼리 또는 변형을 실행할 권한이 있습니다. |
NO_ACCESS |
이 작업은 Admin SDK 컨텍스트 외부에서 실행할 수 없습니다. |
이러한 사전 설정된 액세스 수준을 출발점으로 삼아 where
필터와 서버에서 평가되는 Common Expression Language (CEL) 표현식을 사용하여 @auth
디렉티브에서 복잡하고 강력한 승인 검사를 정의할 수 있습니다.
@auth
지시어를 사용하여 일반적인 승인 시나리오 구현
사전 설정된 액세스 수준은 승인의 출발점입니다.
USER
액세스 수준은 가장 광범위하게 유용한 기본 수준으로 시작할 수 있습니다.
완전히 안전한 액세스는 USER
수준과 사용자 속성, 리소스 속성, 역할, 기타 검사를 확인하는 필터 및 표현식을 기반으로 합니다. USER_ANON
및 USER_EMAIL_VERIFIED
수준은 USER
케이스의 변형입니다.
표현식 문법을 사용하면 작업과 함께 전달된 인증 데이터(인증 토큰의 표준 데이터와 토큰의 맞춤 데이터 모두)를 나타내는 auth
객체를 사용하여 데이터를 평가할 수 있습니다. auth
객체에서 사용할 수 있는 필드 목록은 참조 섹션을 참고하세요.
물론 PUBLIC
가 시작에 적합한 액세스 수준인 사용 사례도 있습니다. 다시 한번 강조하지만 액세스 수준은 항상 출발점이며 강력한 보안을 위해서는 추가 필터와 표현식이 필요합니다.
이제 이 가이드에서는 USER
및 PUBLIC
에서 빌드하는 방법의 예를 제공합니다.
동기를 부여하는 예시
다음 권장사항 예시는 특정 콘텐츠가 결제 계획으로 잠겨 있는 블로깅 플랫폼의 다음 스키마를 참고합니다.
이러한 플랫폼은 Users
및 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")
}
사용자 소유 리소스
Firebase에서는 리소스의 사용자 소유권을 테스트하는 필터와 표현식(예: Posts
의 소유권)을 작성하는 것이 좋습니다.
다음 예에서는 표현식을 사용하여 인증 토큰의 데이터를 읽고 비교합니다. 일반적인 패턴은 where: {authorUid:
{eq_expr: "auth.uid"}}
와 같은 표현식을 사용하여 저장된 authorUid
를 인증 토큰에 전달된 auth.uid
(사용자 ID)와 비교하는 것입니다.
만들기
이 인증 관행은 후속 인증 테스트에서 비교할 수 있도록 인증 토큰의 auth.uid
를 각 새 Post
에 authorUid
필드로 추가하는 것으로 시작합니다.
# 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
})
}
Update
클라이언트가 Post
를 업데이트하려고 하면 저장된 authorUid
를 기준으로 전달된 auth.uid
를 테스트할 수 있습니다.
# 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"
}
)
}
삭제
삭제 작업을 승인하는 데도 동일한 기법이 사용됩니다.
# 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 }
}
목록
# 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 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
}
}
데이터 필터링
Data Connect의 승인 시스템을 사용하면 PUBLIC
과 같은 사전 설정된 액세스 수준과 결합된 정교한 필터를 작성하고 인증 토큰의 데이터를 사용할 수 있습니다.
또한 승인 시스템을 사용하면 다음 예시 중 일부와 같이 기본 액세스 수준 없이 표현식만 사용할 수 있습니다.
리소스 속성으로 필터링
여기서 기본 보안 수준이 PUBLIC
로 설정되어 있으므로 승인은 인증 토큰을 기반으로 하지 않습니다. 하지만 데이터베이스의 레코드를 공개 액세스에 적합하도록 명시적으로 설정할 수 있습니다. 데이터베이스에 visibility
이 'public'으로 설정된 Post
레코드가 있다고 가정해 보겠습니다.
# 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
}
}
사용자 주장별 필터링
여기서는 인증 토큰에서 auth.token.plan
필드로 플래그가 지정된 앱의 'pro' 요금제 사용자를 식별하기 위해 인증 토큰을 전달하는 맞춤 사용자 클레임을 설정했다고 가정합니다. 표현식은 이 필드를 기준으로 테스트할 수 있습니다.
# 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
}
}
순서 + 제한으로 필터링
또는 Post
레코드에서 visibility
를 설정하여 '프로' 사용자에게 제공되는 콘텐츠임을 식별할 수 있지만, 데이터의 미리보기 또는 티저 등록정보의 경우 반환되는 레코드 수를 더 제한할 수 있습니다.
# 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
}
}
역할별 필터링
커스텀 클레임에서 admin
역할을 정의하는 경우 적절하게 작업을 테스트하고 승인할 수 있습니다.
# List all posts unconditionally iff the current user has an admin claim
query AdminListPosts @auth(expr: "auth.token.admin == true") {
posts { ...DisplayPost }
}
@check
및 @redact
디렉티브 이해
@check
지시어는 지정된 필드가 쿼리 결과에 있는지 확인합니다. Common Expression Language (CEL) 표현식은 필드 값을 테스트하는 데 사용됩니다. 디렉티브의 기본 동작은 null
값 노드를 확인하고 거부하는 것입니다.
@redact
지시어는 클라이언트의 응답 일부를 삭제합니다. 삭제된 필드는 여전히 데이터 변경 및 @check
를 비롯한 부작용에 대해 평가되며 결과는 CEL 표현식의 후속 단계에서 계속 사용할 수 있습니다.
Data Connect에서 @check
및 @redact
디렉티브는 승인 확인 컨텍스트에서 가장 자주 사용됩니다. 승인 데이터 조회 관련 논의를 참고하세요.
@check
및 @redact
디렉티브를 추가하여 승인 데이터 조회
일반적인 승인 사용 사례는 데이터베이스(예: 특수 권한 테이블)에 맞춤 승인 역할을 저장하고 이러한 역할을 사용하여 데이터를 생성, 업데이트 또는 삭제하는 변형을 승인하는 것입니다.
승인 데이터 조회를 사용하면 userID를 기반으로 역할을 쿼리하고 CEL 표현식을 사용하여 변형이 승인되었는지 결정할 수 있습니다. 예를 들어 승인된 클라이언트가 영화 제목을 업데이트할 수 있는 UpdateMovieTitle
변형을 작성할 수 있습니다.
이 섹션의 나머지 부분에서는 영화 리뷰 앱 데이터베이스가 MoviePermission
테이블에 승인 역할을 저장한다고 가정합니다.
# 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!
}
변형에서 사용
다음 구현 예에서 UpdateMovieTitle
변형에는 MoviePermission
에서 데이터를 검색하는 query
필드와 작업이 안전하고 강력하도록 하는 다음 디렉티브가 포함됩니다.
- 모든 승인 쿼리 및 검사가 자동으로 완료되거나 실패하도록 하는
@transaction
디렉티브입니다. - 응답에서 쿼리 결과를 생략하는
@redact
지시어. 즉, Data Connect 서버에서 승인 확인이 실행되지만 민감한 정보는 클라이언트에 노출되지 않습니다. 지정된 userID에 수정 권한이 있는지 테스트하는 등 쿼리 결과에서 승인 로직을 평가하는
@check
디렉티브 쌍입니다.
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
})
}
쿼리에서 사용
승인 데이터 조회는 역할 또는 기타 제한사항에 따라 쿼리를 제한하는 데도 유용합니다.
MoviePermission
스키마도 사용하는 다음 예에서 쿼리는 요청자에게 영화를 수정할 수 있는 사용자를 볼 수 있는 적절한 '관리자' 역할이 있는지 확인합니다.
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
}
}
}
승인 시 피해야 할 안티패턴
이전 섹션에서는 @auth
디렉티브를 사용할 때 따라야 하는 패턴을 다룹니다.
피해야 할 중요한 역패턴도 알아두어야 합니다.
쿼리 및 변형 인수에 사용자 속성 ID 및 인증 토큰 매개변수를 전달하지 않음
Firebase Authentication는 인증 흐름을 표시하고 등록된 사용자 ID, 인증 토큰에 저장된 여러 필드와 같은 인증 데이터를 안전하게 캡처하는 강력한 도구입니다.
쿼리 및 변형 인수에 사용자 ID 및 인증 토큰 데이터를 전달하는 것은 권장되지 않습니다.
# 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
액세스 수준을 사용하지 않음
가이드에서 여러 번 설명한 대로 USER
, USER_ANON
, USER_EMAIL_VERIFIED
와 같은 핵심 액세스 수준은 필터 및 표현식으로 개선할 수 있는 승인 확인의 기준점 및 시작점입니다. 요청을 실행하는 사용자를 확인하는 상응하는 필터나 표현식 없이 이러한 수준을 사용하면 기본적으로 PUBLIC
수준을 사용하는 것과 같습니다.
# Antipattern!
# This incorrectly allows any user to view all documents
query ListDocuments @auth(level: USER) {
documents {
id
title
text
}
}
프로토타입 제작 시 PUBLIC
또는 USER
액세스 수준 사용하지 않기
개발 속도를 높이기 위해 모든 작업을 승인하고 코드를 빠르게 테스트할 수 있도록 추가 개선 없이 모든 작업을 PUBLIC
액세스 수준 또는 USER
액세스 수준으로 설정하고 싶을 수 있습니다.
이 방법으로 초기 프로토타입을 완료한 후 NO_ACCESS
에서 PUBLIC
및 USER
수준으로 프로덕션 준비 완료 승인으로 전환합니다.
그러나 이 가이드에 설명된 대로 로직을 추가하지 않고 PUBLIC
또는 USER
로 배포하지 마세요.
# Antipattern!
# This incorrectly allows anyone to delete any post
mutation DeletePost($id: UUID!) @auth(level: PUBLIC) {
post: post_delete(
id: $id,
)
}
인증을 확인되지 않은 이메일 주소에 기반하지 않도록 합니다.
특정 도메인의 사용자에게 액세스 권한을 부여하면 액세스를 제한하는 데 도움이 됩니다. 하지만 누구나 로그인 중에 이메일 소유권을 주장할 수 있습니다. Firebase 인증을 통해 확인된 이메일 주소에만 액세스 권한을 부여해야 합니다.
# 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
})
}
도 확인auth.token.email_verified
mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email_verified && 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로 승인 감사
앞에서 언급한 대로 PUBLIC
및 USER
와 같은 사전 설정된 액세스 수준은 강력한 승인의 시작점이며 추가 필터 및 표현식 기반 승인 검사와 함께 사용해야 합니다.
사용 사례를 신중하게 고려하지 않고는 자체적으로 사용해서는 안 됩니다.
Data Connect는 Firebase CLI의 firebase deploy
를 사용하여 서버에 배포할 때 커넥터 코드를 분석하여 승인 전략을 감사하는 데 도움이 됩니다. 이 감사를 통해 코드베이스를 검토할 수 있습니다.
커넥터를 배포하면 CLI가 커넥터의 기존, 수정된, 새 작업 코드에 대한 평가를 출력합니다.
수정된 작업과 새 작업의 경우 새 작업에서 특정 액세스 수준을 사용하거나 이러한 액세스 수준을 사용하도록 기존 작업을 수정할 때 CLI에서 경고를 표시하고 확인을 요청합니다.
경고 및 메시지는 항상 다음과 같은 경우에 표시됩니다.
PUBLIC
또한 auth.uid
를 사용하여 필터로 확장하지 않으면 다음 액세스 수준에서 경고 및 메시지가 표시됩니다.
USER
USER_ANON
USER_EMAIL_VERIFIED
@auth(insecureReason:)
인수를 사용하여 안전하지 않은 작업 경고 억제
대부분의 경우 PUBLIC
및 USER*
액세스 수준을 사용하는 것이 가장 적절하다고 판단됩니다.
커넥터에 많은 작업이 포함된 경우 일반적으로 경고를 트리거하지만 올바른 액세스 수준을 알고 있는 작업을 생략하는 더 명확하고 관련성 높은 보안 감사 출력을 원할 수 있습니다.
@auth(insecureReason:)
를 사용하여 이러한 작업에 대한 경고를 억제할 수 있습니다.
예를 들면 다음과 같습니다.
query listItem @auth(level: PUBLIC, insecureReason: "This operation is safe to expose to the public.")
{
items {
id name
}
}
앱 증명에 Firebase App Check 사용
인증 및 승인은 Data Connect 보안의 중요한 구성요소입니다. 인증 및 승인을 앱 증명과 결합하면 매우 강력한 보안 솔루션을 만들 수 있습니다.
Firebase App Check를 통한 증명을 사용하면 앱을 실행하는 기기는 Data Connect 작업이 인증된 앱에서 시작되고 요청이 변조되지 않은 인증된 기기에서 시작되었음을 증명하는 앱 또는 기기 증명 제공자를 사용합니다. 이 증명은 앱이 Data Connect에 대해 수행하는 모든 요청에 연결됩니다.
Data Connect에 App Check를 사용 설정하고 앱에 클라이언트 SDK를 포함하는 방법을 알아보려면 App Check 개요를 확인하세요.
@auth(level)
디렉티브의 인증 수준
다음 표에는 모든 표준 액세스 수준과 해당 CEL이 나와 있습니다. 인증 수준은 광범위하게부터 좁게까지 나열됩니다. 각 수준은 다음 수준과 일치하는 모든 사용자를 포함합니다.
수준 | 정의 |
---|---|
PUBLIC |
이 작업은 인증 여부와 관계없이 누구나 실행할 수 있습니다.
고려사항: 모든 사용자가 데이터를 읽거나 수정할 수 있습니다. Firebase에서는 제품 또는 미디어 등 공개적으로 탐색 가능한 데이터에 이 수준의 승인을 권장합니다. 권장사항 예시 및 대안을 참고하세요. @auth(expr: "true") 과 동일합니다.
@auth 필터 및 표현식은 이 액세스 수준과 함께 사용할 수 없습니다. 이러한 표현식은 400 Bad Request 오류와 함께 실패합니다.
|
USER_ANON |
Firebase Authentication로 익명으로 로그인한 사용자를 포함하여 식별된 모든 사용자는 쿼리 또는 변형을 실행할 권한이 있습니다.
참고: USER_ANON 는 USER 의 상위 집합입니다.
고려사항: 이 수준의 승인에 맞게 쿼리와 변형을 신중하게 설계해야 합니다. 이 수준을 사용하면 사용자가 Authentication로 익명으로 로그인할 수 있습니다 (자동 로그인이 사용자 기기에만 연결됨). 이 수준은 자체적으로 데이터가 사용자의 것인지 여부와 같은 다른 검사를 실행하지 않습니다. 권장사항 예시 및 대안을 참고하세요. Authentication 익명 로그인 흐름은 uid 를 실행하므로 USER_ANON 수준은 와 같습니다. @auth(expr: "auth.uid != nil")
|
USER |
Firebase Authentication로 로그인한 모든 사용자는 익명 로그인 사용자를 제외하고 쿼리 또는 변형을 실행할 권한이 있습니다.
고려사항: 이 수준의 승인에 맞게 쿼리와 변형을 신중하게 설계해야 합니다. 이 수준은 사용자가 Authentication로 로그인했는지만 확인하며, 데이터가 사용자에게 속하는지 여부와 같은 다른 검사는 자체적으로 실행하지 않습니다. 권장사항 예시 및 대안을 참고하세요. @auth(expr: "auth.uid != nil &&
auth.token.firebase.sign_in_provider != 'anonymous'")" 와 같습니다.
|
USER_EMAIL_VERIFIED |
인증된 이메일 주소로 Firebase Authentication로 로그인한 모든 사용자는 쿼리 또는 변형을 실행할 권한이 있습니다.
고려사항: 이메일 인증은 Authentication를 사용하여 실행되므로 더 강력한 Authentication 메서드를 기반으로 하므로 이 수준은 USER 또는 USER_ANON 에 비해 보안을 강화합니다. 이 수준은 사용자가 확인된 이메일로 Authentication로 로그인했는지만 확인하며, 데이터가 사용자에게 속하는지 여부와 같은 다른 검사는 자체적으로 실행하지 않습니다. 권장사항 예시 및 대안을 참고하세요.
@auth(expr: "auth.uid != nil &&
auth.token.email_verified")" 와 같습니다. |
NO_ACCESS |
이 작업은 Admin SDK 컨텍스트 외부에서 실행할 수 없습니다.
@auth(expr: "false") 와 같습니다. |
@auth(expr)
용 CEL 참조
이 가이드의 다른 예에서 볼 수 있듯이 Common Expression Language (CEL)에 정의된 표현식을 사용하여 @auth(expr:)
및 @check
지시어를 사용하여 Data Connect의 승인을 제어할 수 있으며 그렇게 해야 합니다.
이 섹션에서는 이러한 디렉티브의 표현식 만들기와 관련된 CEL 문법을 설명합니다.
CEL에 관한 전체 참조 정보는 CEL 사양에 나와 있습니다.
쿼리 및 변형에 전달된 테스트 변수
@auth(expr)
구문을 사용하면 쿼리 및 변형에서 변수에 액세스하고 테스트할 수 있습니다.
예를 들어 vars.status
를 사용하여 $status
와 같은 작업 변수를 포함할 수 있습니다.
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
표현식에 사용할 수 있는 데이터
@auth(expr:)
및 @check(expr:)
CEL 표현식은 모두 다음을 평가할 수 있습니다.
request.operationName
vars
(request.variables
의 별칭)auth
(request.auth
의 별칭)
또한 @check(expr:)
표현식은 다음을 평가할 수 있습니다.
this
(현재 필드의 값)
request.operationName 객체
request.operarationName
객체는 쿼리 또는 변형 중 하나인 작업 유형을 저장합니다.
vars
객체
vars
객체를 사용하면 표현식이 쿼리 또는 변형에 전달된 모든 변수에 액세스할 수 있습니다.
표현식에서 vars.<variablename>
를 정규화된 request.variables.<variablename>
의 별칭으로 사용할 수 있습니다.
# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")
auth
객체
Authentication는 데이터 액세스를 요청하는 사용자를 식별하고 해당 정보를 표현식에서 빌드할 수 있는 객체로 제공합니다.
필터와 표현식에서 auth
를 request.auth
의 별칭으로 사용할 수 있습니다.
auth 객체에는 다음 정보가 포함됩니다.
uid
: 요청하는 사용자에게 할당된 순 사용자 ID입니다.token
: Authentication에서 수집한 값의 맵입니다.
auth.token
의 콘텐츠에 관한 자세한 내용은 인증 토큰의 데이터를 참고하세요.
this
바인딩
바인딩 this
는 @check
디렉티브가 연결된 필드로 평가됩니다. 기본적인 경우 단일 값 쿼리 결과를 평가할 수 있습니다.
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
})
}
조상이 목록이므로 반환된 필드가 여러 번 발생하는 경우 각 값에 바인딩된 this
를 사용하여 각 어커런스를 테스트합니다.
주어진 경로에서 조상이 null
또는 []
인 경우 필드에 도달하지 않으며 해당 경로의 CEL 평가가 건너뜁니다. 즉, this
이 null
이거나 null
가 아닌 경우에만 평가가 실행되며 undefined
인 경우는 평가되지 않습니다.
필드 자체가 목록 또는 객체인 경우 this
는 다음 예와 같이 동일한 구조(객체의 경우 선택된 모든 하위 요소 포함)를 따릅니다.
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
})
}
복잡한 표현식 문법
&&
및 ||
연산자와 결합하여 더 복잡한 표현식을 작성할 수 있습니다.
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
다음 섹션에서는 사용 가능한 모든 연산자를 설명합니다.
연산자 및 연산자 우선순위
다음 표를 통해 연산자와 연산자 우선순위를 참고하세요.
a
및 b
, 필드 f
, 색인 i
는 임의로 주어진 표현식입니다.
연산자 | 설명 | 결합 |
---|---|---|
a[i] a() a.f |
색인, 호출, 필드 액세스 | 왼쪽에서 오른쪽으로 |
!a -a |
단항 부정 | 오른쪽에서 왼쪽으로 |
a/b a%b a*b |
곱셈 연산자 | 왼쪽에서 오른쪽으로 |
a+b a-b |
덧셈 연산자 | 왼쪽에서 오른쪽으로 |
a>b a>=b a<b a<=b |
관계 연산자 | 왼쪽에서 오른쪽으로 |
a in b |
목록 또는 맵에 존재 | 왼쪽에서 오른쪽으로 |
type(a) == t |
유형 비교: t 은 bool, int, float, number, string, list, map, timestamp, duration일 수 있습니다. |
왼쪽에서 오른쪽으로 |
a==b a!=b |
비교 연산자 | 왼쪽에서 오른쪽으로 |
a && b |
조건부 AND | 왼쪽에서 오른쪽으로 |
a || b |
조건부 OR | 왼쪽에서 오른쪽으로 |
a ? true_value : false_value |
3항 표현식 | 왼쪽에서 오른쪽으로 |
인증 토큰의 데이터
auth.token
객체는 다음 값을 포함할 수 있습니다.
필드 | 설명 |
---|---|
email |
계정과 연결된 이메일 주소(있는 경우)입니다. |
email_verified |
true 는 사용자가 email 주소에 대한 액세스 권한이 있는지 확인한 경우입니다. 일부 제공업체는 자동으로 자체 이메일 주소를 확인합니다. |
phone_number |
계정과 연결된 전화번호(있는 경우)입니다. |
name |
사용자의 표시 이름(설정된 경우)입니다. |
sub |
사용자의 Firebase UID입니다. 프로젝트 내에서 고유합니다. |
firebase.identities |
사용자 계정과 연결된 모든 ID의 사전입니다. 사전의 키는 email , phone , google.com , facebook.com , github.com , twitter.com 일 수 있습니다. 사전의 값은 계정과 연결된 각 ID 공급업체의 고유한 식별자 배열입니다. 예를 들어 auth.token.firebase.identities["google.com"][0] 에는 계정과 연결된 첫 번째 Google 사용자 ID가 포함됩니다. |
firebase.sign_in_provider |
토큰을 얻기 위해 사용된 로그인 제공업체입니다. 문자열 custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com 중 하나일 수 있습니다. |
firebase.tenant |
계정과 연결된 tenantId(있는 경우)입니다. 예를 들면 tenant2-m6tyz 입니다. |
JWT ID 토큰의 추가 필드
다음 auth.token
필드에도 액세스할 수 있습니다.
커스텀 토큰 클레임 | ||
---|---|---|
alg |
알고리즘 | "RS256" |
iss |
발급자 | 프로젝트의 서비스 계정 이메일 주소 |
sub |
제목 | 프로젝트의 서비스 계정 이메일 주소 |
aud |
잠재고객 | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
발급 시간 | Unix epoch를 기준으로 하는 현재 시간(초) |
exp |
만료 시간 |
Unix epoch를 기준으로 하는 토큰 만료 시간(초). iat 보다 최대 3,600초 길어질 수 있습니다.
참고: 이 항목은 커스텀 토큰 자체의 만료 시간만 제어합니다. signInWithCustomToken() 으로 사용자가 로그인한 후에는 세션이 무효화되거나 사용자가 로그아웃할 때까지 기기에서 로그인 상태가 유지됩니다.
|
<claims> (선택사항) |
토큰에 포함할 선택적 맞춤 클레임으로, 표현식에서 auth.token (또는 request.auth.token )를 통해 액세스할 수 있습니다. 예를 들어 맞춤 소유권 주장 adminClaim 을 만드는 경우 auth.token.adminClaim 로 액세스할 수 있습니다.
|
다음 단계
- Firebase Data Connect는 권한이 있는 환경에서 쿼리 및 변형을 실행할 수 있는 Admin SDK를 제공합니다.
- 서비스 및 데이터베이스 관리 가이드에서 IAM 보안에 대해 알아보세요.