현재 간단하게 진행중인 프로젝트에서 Firebase의 FireStore를 사용하게 되었다.
다른 사람이 하던 프로젝트를 넘겨받아서 RealtimeDatabase 와 FireStore의 차이점을 제대로 모른채로 작업했다가 이제서야 정리한다.
Data Model :
(RealtimeDatabase) JSON Tree -> 정규화 불편함.
(FireStore) Collection > Document(key - value)
Query
(RealtimeDatabase) 정렬 및 필터링은 가능. But, 동시 필터링 X / 특정 depth의 데이터를 반환할 때, 하위 depth 전체 반환 -> 성능 저하 가능성 O
(FireStore) 정렬 및 필터링 조건문 동시 사용 가능 / 특정 컬렉션이나 컬렉션이 가지고 있는 문서만 반환
Extension
(RealtimeDatabase) 단일db 동시연결 약 10만개, 초당 쓰기 약 1천 회 -> 확장하려면 여러 db로 샤딩 필요.
(FireStore) 샤딩X, 확장이 자동으로 수행됨. 최대 확장한도는 동시 연결수 약 100만개, 초당 쓰기 약 1만회 -> 개별 문서 or 색인의 쓰기 속도에는 제한이 있음(문서 : 초당 1개, 색인 : 초당 500회)
문제가 생겼던 Firestore 규칙에 대해서 알아보자.
firestore에는 document에 대한 접근 및 CRUD 처리에 관한 권한을 설정할 수 있는 규칙이라는게 있음.
어느날, 메일 하나가 도착했다.
!보안 규칙에서 다음 문제가 감지되었습니다.
- 모든 사용자가 전체 데이터베이스를 읽을 수 있습니다.
- 모든 사용자가 전체 데이터베이스에 쓸 수 있습니다.
문제는 규칙에 있었다.
기존에 설정되어있던 규칙은 아래와 같았다.
원래 작업하던 사람이 allow read, write: if false; 였던 규칙이 안되니까 true로만 바꿔버린거같았다.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
이 규칙에 따르면 이 Firestore Project에 등록된 앱을 사용하는 모든 사용자가 DB 내의 모든 Collection 및 문서에 CRUD 작업을 할 수 있다.
그렇기 때문에 경고 메세지가 왔고, 사용자에 따라 접근 권한을 설정해줘야 했다.
보안 규칙에서 특정 사용자에게 권한을 주기 위해서는, 특정 사용자를 구분할 수 있는 인증 절차가 필요하다.
이 작업을 위한 준비물은 세 가지.
먼저 사용자 등록의 경우, Client에서 요청을 할 수도 있지만( createUserWithEmailAndPassword 함수 사용 )
나의 경우에는 단 하나의 사용자(팀 공용 계정)만 필요하기 때문에, 수동으로 Firebase 웹(Project > Build > Authentication)에서 이메일과 비밀번호를 등록했다.
그리고 나서 규칙을 아래와 같이 수정했다.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
수정했다고 하기도 민망할 정도..
"request.auth 가 있으면" read, write 권한을 주도록 수정했다.
request.auth 는 Firebase Auth를 사용하여 인증되었다고 가정하는 사용자 정보를 포함한다.
fun signIn(){
auth.signInWithEmailAndPassword("이메일", "비밀번호")
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
val user = auth.currentUser
Toast.makeText(baseContext, "Authentication succeed : " + user!!.email.toString() ,
Toast.LENGTH_SHORT).show()
} else {
// If sign in fails, display a message to the user.
Toast.makeText(baseContext, "Authentication failed.",
Toast.LENGTH_SHORT).show()
}
}
}