안녕하세요. 이지이지입니다.
이 포스팅을 읽는 분이라면 파이어베이스DB를 사용하고 있다는 것이고,
파이어베이스를 사용하는 이유는
1. 데이터를 웹에 저장하고 사용자들이 변화하는 데이터를 읽고 쓰기를 할 수 있도록 하기 위해
2. 사용자 인증 기능을 구현하기 위해
3. 인증된 사용자만이 데이터를 읽고 쓰게 할 수 있는 권한을 부여하기 위해
이렇게 세가지 정도로 요약할 수 있을 것 같습니다.
하지만 저의 경우 아무리 웹을 돌아다녀보아도, 1에 대한 내용만 많고
2번과 3번에 대한 제대로 된 우리말 콘텐츠는 찾아볼 수가 없었습니다.
그래서 많은 외국 사이트들을 돌아다니면서 깨우친 초보 개발자로서의 노하우를 공유합니다.
2번의 경우에는 저의 지난 포스팅(회원가입)을 참고하시구요.
2번 과정을 거쳐야만 오늘 다룰 파이어베이스DB 권한 관리(규칙 설정)를 사용할 수가 있습니다.
앱인벤터 회원가입 및 로그인 만들기(feat. 이메일 인증, 파이어베이스DB) #1
안녕하세요. 이지이지입니다. 이번 포스팅에서는 앱인벤터2(App Inventor2)에서 회원가입 및 로그인 기능을 만들어 볼텐데요. 여러 사이트들에서 볼 수 있는 이메일인증 기능과 파이어베이스(firebase
egeasy.tistory.com
이제 앱인벤터에서 파이어베이스를 사용할 때
인증된 사용자만 데이터베이스를 읽고 쓸 수 있는 권한 부여에 대해 알아보도록 하겠습니다.
(※ Realtime Database에 대해서만 설명드립니다. 기회가 되면 Firestore Database 권한관리도 다루어 보겠습니다.)
먼저 다음 앱인벤터 파일을 다운받아 참고하시기 바랍니다.
화면구성 |
다음은 파이어베이스 규칙 설정을 테스트해보기 위한 화면구성입니다.
위 화면구성의 흐름을 보자면
[SignIn]을 통해 로그인을 하고, 파이어베이스 인증 서버를 통해 사용자 정보를 받아옵니다.
[쓰기]를 통해 파이어베이스DB에 {"key":"value"}의 json 형식으로 데이터를 입력합니다.
(ex. {"Name":"이지이지"} → 앱인벤터에서 key인 Name을 찾으면 그 값인 "이지이지"를 가져오게 됩니다.
※ key = 파이어베이스DB의 태그(tag)
[읽기]를 통해 [쓰기]로 입력한 데이터가 제대로 입력되었는지 가져와봅니다.
[삭제]를 통해 txt_Delete안에 입력된 key(tag)를 파이어베이스DB에서 찾아 삭제합니다.
[Firebase Test]를 통해 권한부여에 따라 어떤 결과가 나오는지 확인합니다.
블록코딩 |
다음 이미지는 전체 블록을 보여줍니다.
조금 복잡해 보이기는 하나, 조합이 되어 그렇지 코딩 내용이 많은 것은 아닙니다.
이제 이벤트별로 각 블록을 설명드리도록 하겠습니다.
먼저 인증된 사용자만이 데이터베이스에 접근을 할 수 있도록 하기 위한
로그인 기능 블록입니다.
① 파이어베이스 프로젝트의 웹 API키를 변수 APIKeys에 담아둡니다.
웹 API키는 다음 이미지에서 처럼 파이어베이스 콘솔에서 확인할 수 있습니다.
② 파이어베이스 인증 시스템에 접속합니다.
Join으로 연결된 텍스트는 Firebase Auth REST API를 사용한 것입니다.
인증 서버 주소(URL)은 다음과 같습니다.
[API_KEY] 부분에 여러분의 파이어베이스 웹 API키를 넣습니다.
https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=[API_KEY]
③ 파이어베이스 인증 서버로 사용자 정보(이메일주소, 비밀번호)를 전송합니다.
파이어베이스 인증 서버로 보내야 할 정보는 다음과 같습니다.
Property Name(속성 이름) | Type(유형) | Description(설명) |
string | The email the user is signing in with. | |
password | string | The password for the account. |
returnSecureToken | boolean | Whether or not to return an ID and refresh token. Should always be true. ※ 반드시 true 값을 전달해야 합니다. |
다음은 파이어베이스 서버에 사용자 정보를 전송했을 때 서버로부터 받게 되는 정보를 앱인벤터 변수에 저장하기 위한 블록입니다.
블록 설명에 앞서 파이어베이스 인증 서버로부터 받는 정보는 다음과 같습니다.
Property Name(속성 이름) | Type(유형) | Description(설명) |
idToken | string | A Firebase Auth ID token for the authenticated user. 인증된 사용자에 대한 파이어베이스 인증 ID 토큰입니다. |
string | The email for the authenticated user. | |
refresh Token | string | A Firebase Auth refresh token for the authenticated user. idToken은 일정 시간이 지나면 갱신되는데, 그 때 갱신할 때 사용하게 되는 토큰입니다. |
expiresIn | string | The number of seconds in which the ID token expires. ID 토큰이 만료되는 시간(초)입니다. |
localId | string | The uid of the authenticated user. 인증된 사용자의 ID(파이어베이스에서 부여)입니다. |
registered | boolean | Whether the email is for an existing account. |
이 정보는 앱인벤터에서 다음과 같이 JSON 형식으로 받게 됩니다.
{
"localId": "ZY1rJK0eYLg...",
"email": "[user@example.com]",
"displayName": "",
"idToken": "[ID_TOKEN]",
"registered": true,
"refreshToken": "[REFRESH_TOKEN]",
"expiresIn": "3600"
}
① 파이어베이스 인증 서버로부터 받은 정보를 저장할 변수(ResponseData)를 딕셔너리형식으로 생성합니다.
※ 딕셔너리(dictionary)는 JSON 형식과 마찬가지로 {"키":"값"}으로 저장되며, 실제 사전처럼 키를 검색하면 키에 해당하는 값을 받아오게 됩니다.
ex. {"연필":"pencil"} 키인 연필을 찾으면 값인 pencil을 가져오게 됩니다.
② 파이어베이스 인증 서버로부터 받게 되는 idToken을 저장해 둘 변수(idToken)를 생성합니다.
③ 파이어베이스 인증 서버로부터 받게 되는 localId(UID)를 저장해 둘 변수(localId)를 생성합니다.
④ 만약 파이어베이스 인증 서버로부터 받게 되는 정보(responseContent)에 "@"이 포함되어 있다면
→ @이 포함되어 있다면, 서버로부터 이메일주소를 받았다는 의미로 제대로 로그인 되었다는 것을 알 수 있음.
⑤ 알림창을 띄워 로그인이 성공했다는 것을 알려줍니다.
⑥ 변수 ResponseData에 서버로 부터 받는 정보(responseContent)를 저장합니다.
※ JSONTextDecodeWithDictionaries / JsonText "A"
→ JsonText형식으로 된 "A"를 앱인벤터가 이해할 수 있도록 JSON Text를 해독하여 딕셔너리 형태로 만들어라.
⑦~⑧ 딕셔너리 ResponseData에서 키 idToken / localId을 찾아 그 값을 변수 idToken / localId에 저장합니다.
다음은 [쓰기]버튼을 클릭했을 때, 파이어베이스DB에 인증된 사용자만이 DB에 데이터를 입력하는 블록입니다.
이에 앞서 테스트할 Realtime Database 구조는 다음과 같습니다.
① Firebase Realtime Database 경로를 변수 path에 저장해둡니다.
②~④ 데이터를 입력할 Realtime Database의 Project Bucket(상위 tag, 폴더 개념)을 설정합니다.
→ https://egeasylec...com/User_Data/localId
※ localId는 로그인 했을 때, 파이어베이스 인증 서버로부터 받아 두었습니다. 상단의 로그인 부분 참고
※ 이 포스팅에서 테스트 할 localId는 위 이미지에 있는 Wo...p2입니다.
⑤~⑥ 위 경로에 쓸 수 있는 권한을 변수 idToken에 저장된 토큰을 가진 사용자로 제한합니다.
⑦~⑬ 위 경로에 키는 txt_key로, 값은 txt_value로 하여 데이터를 입력합니다.
→ 파이어베이스 DB는 JSON형식으로 데이터를 저장하므로, {"key":"value"}형식으로 데이터를 전달해야 합니다.
→ key와 value부분에 입력할 데이터가 만약 텍스트라면 쌍따옴표(" ")로 둘러싸주어야 하며,
입력할 데이터가 숫자 형식이라면 쌍따옴표는 필요 없습니다.
→ 위의 데이터베이스 구조에서는 {"name":"이지이지"}로 데이터를 전송한 결과입니다.
→ 이미 키가 존재할 경우 값을 덮어쓰게 되며 키가 존재하지 않을 경우 새로운 태그를 만들고 값을 저장하게 됩니다.
[읽기] 버튼을 클릭했을 때, 파이어베이스 DB에 인증된 사용자만이 데이터를 읽어 오게하는 블록입니다.
①~⑤ 파이어베이스 Realtime Database에서 데이터를 받아 올 경로(태그의 경로)를 설정합니다.
→ txt_key 컴포넌트에 입력된 태그(키)에 저장된 값을 가져옵니다.
→ 위에서 예시로 든 데이터베이스 구조에서 "이지이지"를 불러오기 위해서는 txt_key 컴포넌트에 name을 입력하는 것입니다.
⑥~⑦ 파이어베이스 DB에서 ⑦의 idToken을 가진 사용자만 데이터를 읽을 수 있게 합니다.
⑧ ①~⑦의 설정에 따라 데이터를 받아오라는 명령입니다.
⑨ 데이터베이스로부터 값을 전달 받았을 때 실행되는 블록으로 lbl_ReadData의 텍스트 값을 데이터베이스로부터 전달받은 내용으로 하라는 명령입니다.
다음은 [삭제] 버튼을 클릭했을 때, 파이어베이스 DB에서 인증된 사용자만이 데이터를 삭제하게 하는 블록입니다.
①~⑤ 데이터베이스에서 삭제할 태그(키)의 경로를 설정합니다. 태그와 값 모두 삭제됩니다.
⑥~⑦ ⑦의 idToken을 가진 사용자만이 삭제할 수 있도록 합니다.
⑧ 삭제를 하라는 명령입니다.
다음은 파이어베이스 DB의 여러 권한(전체 사용자 허용, 전체 사용자 불가, 인증된 사용자만 허용, 특정 idToken을 가진 사용자만 허용)을 테스트해보기 위한 블록입니다.
※ 아래의 엡인벤터에 내장된 파이어베이스 블록으로는 사실 권한 설정에 한계가 있습니다.
전체 사용자에게 허용 또는 전체 사용자 불가에만 적용 가능하며, 인증된 사용자만 허용한다던가 특정 idToken을 가진 사용자만 허용하기 위해서는 위의 웹 컴포넌트를 사용해야 합니다.
① 파이어베이스의 프로젝트 버킷(태그)을 User_Data로 합니다.
② User_Data 아래에 있는 모든 태그를 불러옵니다.
③ lbl_Result 컴포넌트의 텍스트를 파이어베이스 DB로 부터 받은 값으로 합니다.
→ 권한이 주어져 있다면 User_Data 아래에 있는 모든 태그를 불러오게 되고,
권한이 없다면 불러올 수 없습니다.
④ 파이어베이스에서 오류가 발생한다면(이 경우 권한이 없어 접근이 불가능하다면) 컴포넌트 lbl_Result의 텍스트를 파이어베이스에서 보여주는 오류메시지로 합니다.
이제 가장 중요한 파이어베이스 Realtime Database에서 규칙 설정(권한 부여)을 하는 방법에 대해 알아보겠습니다.
다음은 Realtime Database의 기본 규칙입니다.
많은 사용자들이 다음과 같이 사용하고 있으며,
계속해서 파이어베이스로부터 보안규칙이 위험하다는 알림이 올 것입니다.
위의 규칙은 모든 사용자들에게 모든 경로에 대해
읽기(".read")도 허용("true")하고 쓰기(".write")도 허용하는 규칙입니다.
그래서 경고 메시지가 계속해서 오는 것입니다.
다음 규칙은 모든 사용자들에게 모든 경로에 대해
읽기 및 쓰기를 금지하는 규칙입니다.
".read": false,
".write": false
위에서 보듯이 허용할 때는 true로 금지할 때는 false로 지정하면 됩니다.
다음 규칙은 모든 사용자들에게 모든 경로에 대해 읽기는 허용하고,
쓰기는 로그인한(인증된) 사용자로 제한하는 규칙입니다.
".read": true,
".write": "auth.uid != null"
파이어베이스 Realtime Database는 모든 경로 뿐만 아니라 특정한 하위 경로(태그, 프로젝트 버킷)에 대해서만 규칙을 설정할 수 있습니다.
맨 처음에 본 저의 테스트용 데이터베이스 구조를 다시 보면,
egeasylec-default-rtdb
--- User_Data
------ Enq...Ff2
------ Rsz...hK2
------ WoP...rp2
------ u7S...ny2 로 되어 있습니다.
경로에 권한을 부여하는 방법은
1. 모든 경로에 권한을 부여할 경우: "rules": { 아래에 바로 작성
2. User_Data와 그 하위경로에 권한을 부여할 경우:
rules 아래에 권한을 부여할 태그 이름을 써주고 규칙설정을 하면 됩니다.
{
"rules": {
"User_Data": {
".read": "auth.uid != null",
".write": "auth.uid != null"
}
}
}
3. 같은 수준의 경로에 공통된 권한을 부여할 경우:
만약 다음 처럼 데이터베이스 구조가 이루어져 있고,
같은 수준의 경로에 권한을 부여하고 싶을 때는, $(와일드카드)를 사용합니다.
egeasylec-default-rtdb
--- User_Data
------ egeasy
------ rksekk
------ dkfkekak
--- School_Data
--- Nation_Data
위의 예에서 같은 수준의 경로라 하면 egeasylec-default-rtdb-User_Data 아래 egeasy, rksekk, dkfkekak가 User_Data의 첫 번째 하위수준에 있으므로 모두 함께 권한을 지정해 줄 수 있습니다.
첫 번째 하위 경로의 이름을 개발자가 구분하기 쉽게 원하는 이름을 붙여주고 앞에 $만 붙여주면 됩니다.
여기에서 첫 번째 하위 경로의 이름을 ID라고 정한다면 $ID로 써 주고 권한을 부여하면 됩니다.
아래 규칙을 참고하시기 바랍니다.
{
"rules": {
"User_Data": {
"$ID": {
".read": true
".write": false
}
}
}
}
이제 이를 응용하여 마지막으로 특정한 경로(태그)에 특정한 사용자만 접근 권한을 가능하게 할 경우에는,
사용자의 localId를 태그로 지정하고 사용자의 localId와 태그가 같은 경우 읽기나 쓰기 권한을 부여하는 것입니다.
그렇다면 처음부터 사용자가 가입할 때 사용자의 localId를 태그로 구성해 두는 것이 좋습니다.
위의 예로 든 데이터베이스 구조가 사용자의 localId를 태그로 구성해 두고 모두 User_Data 아래 첫 번째 하위 경로에 있는 경우입니다.
이를 규칙으로 설정하면 다음과 같습니다.
{
"rules": {
"User_Data": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
이제 이러한 데이터베이스 규칙을 가지고 4가지 경우 정도만 예로 테스트해 보겠습니다.
1. 모든 사용자에게 모든 경로의 데이터를 읽고 쓰게 허용한 경우
: 로그인 하지 않았음에도 불구하고 데이터를 읽을 수 있습니다.
2. 모든 사용자에게 모든 경로의 데이터를 읽고 쓰는 것을 금지할 경우
: 아무것도 하지 않아도, 접근을 허용하지 않는다는 메시지를 받았습니다.
3. 사용자의 localId로 된 태그에 그 사용자만 읽고 쓰는 것을 허용한 경우
: 로그인한 사용자의 localId에서만 정보를 읽고 쓸 수 있습니다.
※ 로그인한 사용자임에도 불구하고, Firebase Test에서 "Permission denied"로 뜨는 이유는,
위에서도 언급했듯이 파이어베이스 컴포넌트를 사용했기 때문입니다.
파이어베이스 컴포넌트는 사용자의 인증 정보를 서버로 보낼 수 없기 때문에,
데이터베이스 규칙(권한설정)과 함께 파이어베이스를 사용하기 위해서는 웹 컴포넌트를 사용해야 합니다.
이제 긴 포스팅을 끝맺도록 하겠습니다.
무려 5일에 걸쳐 짬짬이 글을 썼습니다.
부디 앱인벤터에서 파이어베이스 규칙 설정으로 헤매고 있으셨다면 많은 도움이 되길 바라겠습니다.
의문 사항이 있으시면 쪽지로 남겨주세요~~~
댓글