학습 목표와 사전 지식
목표: permission-denied를 재현한 요청과 소유자 규칙·쿼리를 짝지어 수정합니다.
사전 지식: Firestore 컬렉션/문서 경로, Auth UID, 개발용 Emulator
Firestore Rules는 결과에서 비허용 문서만 걸러주지 않습니다. 요청이 허용되는 범위만 읽는다는 것을 쿼리가 증명해야 합니다. 로그인 성공만으로 타인의 문서를 읽을 권한이 생기지는 않습니다.
증상과 최소 재현
Missing or insufficient permissions.와 code: permission-denied가 난 작업을 get, list, create, update, delete 중 하나로 기록합니다. 개발 환경에 ownerId가 alice인 notes/a와 bob인 notes/b를 준비합니다. 아래 규칙에서 alice로 전체 notes 목록을 읽으면 소유자 범위를 보장하지 못해 거부될 수 있습니다. Admin SDK 테스트는 Rules를 우회하므로 이 재현에 사용하지 않습니다.
firestore.rules · 전체 파일; 소유자 메모 최소 규칙
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /notes/{noteId} {
function signedIn() { return request.auth != null; }
function owner() {
return signedIn() && resource.data.ownerId == request.auth.uid;
}
allow read, delete: if owner();
allow create: if signedIn()
&& request.resource.data.keys().hasOnly(['ownerId', 'text'])
&& request.resource.data.ownerId == request.auth.uid
&& request.resource.data.text is string
&& request.resource.data.text.size() <= 500;
allow update: if owner()
&& request.resource.data.diff(resource.data).affectedKeys().hasOnly(['text'])
&& request.resource.data.text is string
&& request.resource.data.text.size() <= 500;
}
}
}
src/notes.js · 전체 모듈; db와 인증 관찰이 끝난 user를 전달
import { collection, getDocs, query, where } from 'firebase/firestore';
export async function readMyNotes(db, user) {
if (!user) throw new Error('로그인 후 실행하세요.');
const q = query(collection(db, 'notes'), where('ownerId', '==', user.uid));
const snapshot = await getDocs(q);
return snapshot.docs.map((item) => ({ id: item.id, ...item.data() }));
}

수정 위치와 이유
src/notes.js의 getDocs(collection(db, “notes”)) 호출을 위 소유자 쿼리로 교체합니다. Rules를 모두 열어 성공시키는 방식은 사용하지 않습니다. create는 새 문서(request.resource.data)를 검사하고 update는 기존 소유자(resource.data)를 확인한 뒤 변경 가능한 필드를 text로 제한합니다. ownerId를 바꾸는 업데이트는 거부됩니다. delete에는 새 문서가 없으므로 기존 문서로 소유권을 판단합니다.
| 시도 | 기대 결과 |
|---|---|
| alice가 ownerId: alice 메모 작성 | 허용 |
| alice가 ownerId: bob 메모 작성 | 거부 |
| alice가 notes/b 단건 읽기 | 거부 |
| alice가 ownerId == alice 목록 조회 | 허용 |
| alice가 자신의 ownerId 변경 | 거부 |
| 비로그인 목록 조회 | 거부 |
수정 후에도 실패하면
onAuthStateChanged의 최초 결과 전에 요청하지 않았는지, 앱 projectId와 배포 대상, 에뮬레이터 연결 여부, 정확한 match 경로를 확인합니다. 배포된 규칙 전파에 시간이 걸릴 수 있습니다. 실패가 failed-precondition으로 바뀌면 필요한 인덱스 문제를 따로 확인하세요. 규칙 합치기 전 다른 경로의 넓은 allow가 OR로 접근을 허용하지 않는지도 검토합니다.
직접 확인할 결과
표의 6개 요청을 클라이언트 인증 문맥별로 실행
규칙 배포 프로젝트 및 파일 비교
실패 코드와 요청 종류를 기록
검증 범위와 기준일
공식 문서 확인일: 2026-09-13. 웹 SDK 예제는 모듈형 API 기준입니다. 이 글의 코드·구조 정적 검토와 실제 클라우드 인증·저장·배포 검증을 구분합니다. 본인 개발 Firebase 프로젝트의 실제 인증·권한·배포 요청은 이 편집 환경에서 실행하지 않았습니다.
이어서 학습하기
- Firebase Auth unauthorized-domain 오류 해결: 로그인 도메인 설정 확인
- Firebase Storage 이미지 오류 해결: 403·404·token·Rules 확인법
공식 문서
이 글이 도움이 되었나요?
Firebase 학습 순서
필수 13개 · 전체 19개
읽음 기록 관리
전체 과정 목차 (19개)
- 필수 길잡이 · Firebase 실무 로드맵: Auth, Firestore, Storage, Functions
- 필수 학습 · Firebase 초기화 구조: Next.js firebase.ts 설계 기준
- 필수 학습 · Firebase Authentication 사용 기준: 로그인 유지와 비밀번호 재설정
- 필수 학습 · Firebase 보안 규칙 설계: Firestore와 Storage 권한 관리하기
- 필수 학습 · Firestore CRUD 사용법: 컬렉션 구조와 읽기 쓰기 흐름
- 필수 학습 · Firebase Auth Context 설계: 로그인 권한과 라우팅 관리하기
- 필수 학습 · Firebase Storage 이미지 업로드 사용법: 상품 이미지 관리 흐름 만들기
- 필수 학습 · Firebase Custom Claims 사용법: 관리자 권한 구분하기
- 필수 학습 · Firebase Functions v2 사용법: 트리거 배포 Secret 처리
- 필수 학습 · Firestore seed data 설계: 리뷰 더미 데이터 구조 잡기
- 선택 참고 · Firebase 배포 제외 파일 설정: firebase.json의 ignore 사용법
- 선택 참고 · Firebase Firestore 인덱스 삭제 질문 해결: 배포 중 안전하게 판단하기
- 선택 참고 · Firebase Auth unauthorized-domain 오류 해결: 로그인 도메인 설정 확인
- 선택 참고 · Firebase permission-denied 오류 해결: Firestore Rules 체크리스트 현재 글
- 선택 참고 · Firebase Storage 이미지 오류 해결: 403·404·token·Rules 확인법
- 선택 참고 · Firebase CORS 오류 해결: Storage 이미지 업로드가 막힐 때 확인할 설정
- 필수 선수 · Firebase 실무 오류 해결 모음: Storage, Firestore, Auth 체크리스트
- 필수 학습 · Firestore undefined 오류 해결: 선택 필드가 저장을 막을 때
- 필수 학습 · Firestore arrayUnion 중첩 배열 오류: 배열을 그대로 넘기면 실패하는 이유
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.