이 페이지는 보안 규칙 구조화 및 보안 규칙 조건 작성 의 개념을 기반으로 Cloud Firestore 보안 규칙이 쿼리와 상호작용하는 방식을 설명합니다. 보안 규칙이 작성할 수 있는 쿼리에 어떤 영향을 미치는지 자세히 살펴보고 쿼리가 보안 규칙과 동일한 제약 조건을 사용하도록 하는 방법을 설명합니다. 이 페이지에서는 limit
및 orderBy
와 같은 쿼리 속성을 기반으로 쿼리를 허용하거나 거부하는 보안 규칙을 작성하는 방법도 설명합니다.
규칙은 필터가 아닙니다.
문서를 검색하기 위해 쿼리를 작성할 때 보안 규칙은 필터가 아니라는 점을 명심하십시오. 쿼리는 전부 아니면 전무입니다. 시간과 리소스를 절약하기 위해 Cloud Firestore는 모든 문서의 실제 필드 값 대신 잠재적인 결과 집합에 대해 쿼리를 평가합니다. 쿼리가 잠재적으로 클라이언트에 읽기 권한이 없는 문서를 반환할 수 있는 경우 전체 요청이 실패합니다.
쿼리 및 보안 규칙
아래 예에서 볼 수 있듯이 보안 규칙의 제약 조건에 맞게 쿼리를 작성해야 합니다.
auth.uid
를 기반으로 문서 보안 및 쿼리
다음 예는 보안 규칙으로 보호되는 문서를 검색하는 쿼리를 작성하는 방법을 보여줍니다. story
문서 모음이 포함된 데이터베이스를 고려하십시오.
/스토리/{storyid}
{
title: "A Great Story",
content: "Once upon a time...",
author: "some_auth_id",
published: false
}
title
및 content
필드 외에도 각 문서는 액세스 제어에 사용할 author
및 published
필드를 저장합니다. 이 예에서는 앱이 Firebase 인증 을 사용하여 author
필드를 문서를 만든 사용자의 UID로 설정한다고 가정합니다. Firebase 인증은 보안 규칙의 request.auth
변수도 채웁니다.
다음 보안 규칙은 request.auth
및 resource.data
변수를 사용하여 각 story
에 대한 읽기 및 쓰기 액세스 권한을 해당 작성자로 제한합니다.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Only the authenticated user who authored the document can read or write
allow read, write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
앱에 사용자가 작성한 story
문서 목록을 표시하는 페이지가 포함되어 있다고 가정합니다. 다음 쿼리를 사용하여 이 페이지를 채울 수 있다고 예상할 수 있습니다. 그러나 이 쿼리는 보안 규칙과 동일한 제약 조건을 포함하지 않기 때문에 실패합니다.
유효 하지 않음: 쿼리 제약 조건이 보안 규칙 제약 조건과 일치하지 않습니다.
// This query will fail
db.collection("stories").get()
현재 사용자가 실제로 모든 story
문서의 작성자인 경우에도 쿼리가 실패합니다. 이 동작의 이유는 Cloud Firestore가 보안 규칙을 적용할 때 데이터베이스에 있는 문서의 실제 속성이 아니라 잠재적인 결과 집합에 대해 쿼리를 평가하기 때문입니다. 쿼리에 보안 규칙을 위반하는 문서가 포함될 수 있는 경우 쿼리가 실패합니다.
반대로 다음 쿼리는 author
필드에 대한 보안 규칙과 동일한 제약 조건을 포함하기 때문에 성공합니다.
유효함 : 쿼리 제약 조건이 보안 규칙 제약 조건과 일치합니다.
var user = firebase.auth().currentUser;
db.collection("stories").where("author", "==", user.uid).get()
필드를 기반으로 문서 보안 및 쿼리
쿼리와 규칙 간의 상호 작용을 추가로 보여주기 위해 아래의 보안 규칙은 published
필드가 true
로 설정된 모든 사용자가 story
문서를 읽을 수 있도록 stories
컬렉션에 대한 읽기 액세스를 확장합니다.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Anyone can read a published story; only story authors can read unpublished stories
allow read: if resource.data.published == true || (request.auth != null && request.auth.uid == resource.data.author);
// Only story authors can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
게시된 페이지에 대한 쿼리에는 보안 규칙과 동일한 제약 조건이 포함되어야 합니다.
db.collection("stories").where("published", "==", true).get()
쿼리 제약 조건 .where("published", "==", true)
는 모든 결과에 대해 resource.data.published
가 true
임을 보장합니다. 따라서 이 쿼리는 보안 규칙을 충족하고 데이터를 읽을 수 있습니다.
in
및 array-contains-any
쿼리
규칙 세트에 대해 in
또는 array-contains-any
쿼리 절을 평가할 때 Cloud Firestore는 각 비교 값을 개별적으로 평가합니다. 각 비교 값은 보안 규칙 제약 조건을 충족해야 합니다. 예를 들어 다음 규칙의 경우:
match /mydocuments/{doc} {
allow read: if resource.data.x > 5;
}
유효 하지 않음: 쿼리는 모든 잠재적 문서에 대해 x > 5
를 보장하지 않습니다.
// This query will fail
db.collection("mydocuments").where("x", "in", [1, 3, 6, 42, 99]).get()
유효 함: 쿼리는 모든 잠재적 문서에 대해 x > 5
를 보장합니다.
db.collection("mydocuments").where("x", "in", [6, 42, 99, 105, 200]).get()
쿼리에 대한 제약 조건 평가
보안 규칙은 제약 조건에 따라 쿼리를 수락하거나 거부할 수도 있습니다. request.query
변수에는 쿼리의 limit
, offset
및 orderBy
속성이 포함됩니다. 예를 들어 보안 규칙은 검색되는 최대 문서 수를 특정 범위로 제한하지 않는 모든 쿼리를 거부할 수 있습니다.
allow list: if request.query.limit <= 10;
다음 규칙 집합은 쿼리에 적용되는 제약 조건을 평가하는 보안 규칙을 작성하는 방법을 보여줍니다. 이 예제는 다음 변경 사항으로 이전 stories
규칙 세트를 확장합니다.
- 규칙 세트는 읽기 규칙을
get
및list
에 대한 규칙으로 분리합니다. -
get
규칙은 단일 문서의 검색을 공용 문서 또는 사용자가 작성한 문서로 제한합니다. -
list
규칙은get
과 동일한 제한 사항을 쿼리에 적용합니다. 또한 쿼리 제한을 확인한 다음 제한이 없거나 제한이 10보다 큰 모든 쿼리를 거부합니다. - 규칙 세트는 코드 중복을 피하기 위해
authorOrPublished()
함수를 정의합니다.
service cloud.firestore {
match /databases/{database}/documents {
match /stories/{storyid} {
// Returns `true` if the requested story is 'published'
// or the user authored the story
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
// Deny any query not limited to 10 or fewer documents
// Anyone can query published stories
// Authors can query their unpublished stories
allow list: if request.query.limit <= 10 &&
authorOrPublished();
// Anyone can retrieve a published story
// Only a story's author can retrieve an unpublished story
allow get: if authorOrPublished();
// Only a story's author can write to a story
allow write: if request.auth.uid == resource.data.author;
}
}
}
컬렉션 그룹 쿼리 및 보안 규칙
기본적으로 쿼리는 단일 컬렉션으로 범위가 지정되며 해당 컬렉션에서만 결과를 검색합니다. 컬렉션 그룹 쿼리 를 사용하면 동일한 ID를 가진 모든 컬렉션으로 구성된 컬렉션 그룹에서 결과를 검색할 수 있습니다. 이 섹션에서는 보안 규칙을 사용하여 컬렉션 그룹 쿼리를 보호하는 방법을 설명합니다.
컬렉션 그룹을 기반으로 문서 보안 및 쿼리
보안 규칙에서 컬렉션 그룹에 대한 규칙을 작성하여 컬렉션 그룹 쿼리를 명시적으로 허용해야 합니다.
-
rules_version = '2';
규칙 세트의 첫 번째 행입니다. 컬렉션 그룹 쿼리에는 보안 규칙 버전 2의 새로운 재귀 와일드카드{name=**}
동작이 필요합니다. -
match /{path=**}/ [COLLECTION_ID] /{doc}
를 사용하여 컬렉션 그룹에 대한 규칙을 작성합니다.
예를 들어 posts
하위 컬렉션을 포함하는 forum
문서로 구성된 포럼을 고려하십시오.
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
}
이 애플리케이션에서는 소유자가 게시물을 편집할 수 있고 인증된 사용자가 읽을 수 있도록 합니다.
service cloud.firestore {
match /databases/{database}/documents {
match /forums/{forumid}/posts/{post} {
// Only authenticated users can read
allow read: if request.auth != null;
// Only the post author can write
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
모든 인증된 사용자는 단일 포럼의 게시물을 검색할 수 있습니다.
db.collection("forums/technology/posts").get()
하지만 모든 포럼에서 현재 사용자의 게시물을 보여주고 싶다면 어떻게 해야 할까요? 컬렉션 그룹 쿼리 를 사용하여 모든 posts
컬렉션에서 결과를 검색할 수 있습니다.
var user = firebase.auth().currentUser;
db.collectionGroup("posts").where("author", "==", user.uid).get()
보안 규칙에서 posts
컬렉션 그룹에 대한 읽기 또는 나열 규칙을 작성하여 이 쿼리를 허용해야 합니다.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Authenticated users can query the posts collection group
// Applies to collection queries, collection group queries, and
// single document retrievals
match /{path=**}/posts/{post} {
allow read: if request.auth != null;
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth != null && request.auth.uid == resource.data.author;
}
}
}
그러나 이러한 규칙은 계층 구조에 관계없이 posts
ID가 있는 모든 컬렉션에 적용됩니다. 예를 들어 이러한 규칙은 다음 posts
모음 모두에 적용됩니다.
-
/posts/{postid}
-
/forums/{forumid}/posts/{postid}
-
/forums/{forumid}/subforum/{subforumid}/posts/{postid}
필드 기반 보안 컬렉션 그룹 쿼리
단일 컬렉션 쿼리와 마찬가지로 컬렉션 그룹 쿼리도 보안 규칙에서 설정한 제약 조건을 충족해야 합니다. 예를 들어 위의 stories
예에서와 같이 각 포럼 게시물에 published
필드를 추가할 수 있습니다.
/forums/{forumid}/posts/{postid}
{
author: "some_auth_id",
authorname: "some_username",
content: "I just read a great story.",
published: false
}
그런 다음 published
상태 및 게시물 author
를 기반으로 posts
컬렉션 그룹에 대한 규칙을 작성할 수 있습니다.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// Returns `true` if the requested post is 'published'
// or the user authored the post
function authorOrPublished() {
return resource.data.published == true || request.auth.uid == resource.data.author;
}
match /{path=**}/posts/{post} {
// Anyone can query published posts
// Authors can query their unpublished posts
allow list: if authorOrPublished();
// Anyone can retrieve a published post
// Authors can retrieve an unpublished post
allow get: if authorOrPublished();
}
match /forums/{forumid}/posts/{postid} {
// Only a post's author can write to a post
allow write: if request.auth.uid == resource.data.author;
}
}
}
이러한 규칙을 사용하여 웹, Apple 및 Android 클라이언트는 다음 쿼리를 만들 수 있습니다.
누구나 포럼에서 게시된 게시물을 검색할 수 있습니다.
db.collection("forums/technology/posts").where('published', '==', true).get()
누구나 모든 포럼에서 작성자가 게시한 게시물을 검색할 수 있습니다.
db.collectionGroup("posts").where("author", "==", "some_auth_id").where('published', '==', true).get()
작성자는 모든 포럼에서 게시된 게시물과 게시되지 않은 게시물을 모두 검색할 수 있습니다.
var user = firebase.auth().currentUser; db.collectionGroup("posts").where("author", "==", user.uid).get()
컬렉션 그룹 및 문서 경로를 기반으로 문서 보안 및 쿼리
경우에 따라 문서 경로를 기반으로 컬렉션 그룹 쿼리를 제한할 수 있습니다. 이러한 제한을 만들기 위해 필드를 기반으로 문서 보안 및 쿼리에 동일한 기술을 사용할 수 있습니다.
여러 주식 및 암호화폐 거래소 간의 각 사용자 거래를 추적하는 애플리케이션을 고려하십시오.
/users/{userid}/exchange/{exchangeid}/transactions/{트랜잭션}
{
amount: 100,
exchange: 'some_exchange_name',
timestamp: April 1, 2019 at 12:00:00 PM UTC-7,
user: "some_auth_id",
}
user
필드를 확인하십시오. 문서의 경로에서 어떤 사용자가 transaction
문서를 소유하고 있는지 알고 있지만 다음 두 가지 작업을 수행할 수 있기 때문에 각 transaction
문서에 이 정보를 복제합니다.
문서 경로에 특정
/users/{userid}
가 포함된 문서로 제한된 컬렉션 그룹 쿼리를 작성합니다. 예를 들어:var user = firebase.auth().currentUser; // Return current user's last five transactions across all exchanges db.collectionGroup("transactions").where("user", "==", user).orderBy('timestamp').limit(5)
한 사용자가 다른 사용자의
transaction
문서를 검색할 수 없도록transactions
컬렉션 그룹의 모든 쿼리에 대해 이 제한을 적용합니다.
보안 규칙에 이 제한을 적용하고 user
필드에 대한 데이터 유효성 검사를 포함합니다.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{path=**}/transactions/{transaction} {
// Authenticated users can retrieve only their own transactions
allow read: if resource.data.user == request.auth.uid;
}
match /users/{userid}/exchange/{exchangeid}/transactions/{transaction} {
// Authenticated users can write to their own transactions subcollections
// Writes must populate the user field with the correct auth id
allow write: if userid == request.auth.uid && request.data.user == request.auth.uid
}
}
}
다음 단계
- 역할 기반 액세스 제어에 대한 자세한 예는 사용자 및 그룹의 데이터 액세스 보안 을 참조하십시오.
- 보안 규칙 참조 를 읽으십시오.