데이터베이스

자료 vs 정보
- 자료 - 현실 세계에서 벌어지는 일들을 단순한 방법으로 관찰하고 측정해서 얻은 값.
- 정보 - 그 자료를 처리해서 얻을 수 있는 결과.
데이터베이스
- 데이터 - 자료, 베이스 - 모여있는 장소.
- 데이터 베이스는 특별한 의미가 있다기 보단 자료를 담고 있는 것.
DBMS와 SQL
- 데이터베이스 관리 시스템(database management system).
- 사용자와 데이터베이스 사이에서 사용자의 요구에 따라 정보를 생성해 주고 데이터베이스를 관리해 주는 소프트웨어.
- 구조화 질의어 (Structured Query Language).
- 관계형 데이터베이스 관리 시스템의 데이터를 관리하기 위해 설계된 특수 목적의 프로그래밍 언어.
- 관계형 데이터베이스 관리 시스템에서 자료의 검색과 관리, 데이터베이스 스키마 생성과 수정, 데이터베이스 객체 접근 조정 관리를 위해 고안.
RDBMS
- 관계형 데이터베이스 관리 시스템(relational database management system).
- RDBMS에서 데이터를 뽑아오는 언어가 SQL임.
- 엑셀처럼 table, column, row 으로 데이터를 구성함.
- CRUD로 작성함.
- 테이블이 다른 테이블들과 관계를 맺고 모여있는 집합체를 나타내기 위해 외래 키(foreign key)라는 것을 사용함.

NoSQL
- Not Only SQL, 규칙 없이 자유롭게 질의 가능.
- 빅데이터같이 한두 개의 자료는 유실 되도 괜찮은 대규모 데이터를 다룰 때 자주 사용함. (단, 의료분야처럼 안되는 경우도 있음.)
RDBMS와 NoSQL의 장단점
- RDBMS 장점 - 중복된 데이터가 없음 (데이터 무결성). 데이터 관리가 확실함.
- RDBMS 단점 - DB 설계가 어렵고 속도가 느림.
- NOSQL 장점 - 만들기 쉽고 속도가 빠름.
- NOSQL 단점 - 데이터가 없더라도 받아들이기 때문에 무결성이 없음. 질문을 잘해야 속도가 빠른 장점을 활용할 수 있음.
RDBMS와 NOSQL 상황에 맞게 사용함. 그리고 RDBMS라고 해서 무조건 느린 것도 아님. nosql도 예외처리를 통해 데이터 유실을 막을 수 있음.
언제 사용해야 할까?
RDBMS는 데이터 구조가 명확하며 변경 될 여지가 없으며 명확한 스키마가 중요한 경우 사용하는 것이 좋음. 또한 중복된 데이터가 없어(데이터 무결성) 변경이 용이하기 때문에 관계를 맺고 있는 데이터가 자주 변경이 이루어지는 시스템에 적합함.
NoSQL은 정확한 데이터 구조를 알 수 없고 데이터가 변경/확장이 될 수 있는 경우에 사용하는 것이 좋음. Update가 많이 이루어지지 않는 시스템이 좋으며 막대한 데이터를 저장해야 해서 Database를 Scale-Out(접속된 서버의 대수를 늘려 처리 능력을 향상시키는 것)를 해야 되는 시스템에 적합함.
인증 방식(로그인)의 변화
1. 계정정보를 요청 헤더에 넣는 방식
가장 보안이 낮은 방식은 계정정보를 요청에 담아 보내는 방식. HTTP 요청에 인증할 수단에 비밀번호를 넣음.

❶ 사용자에게 입력받은 id,pw를 서버에 전달한다.
❷ RDBMS 등 데이터 베이스에서 데이터를 확인한다.
❸ 유저 정보를 인증한다.
(장점)
- 인증을 빠르게 테스트 해볼 수 있음.
(단점)
- 보안에 매우 취약함.
- 서버에서는 신호가 올때마다 Id,Pw를 통해 유저가 맞는지 인증해야 함. 이는 비효율적임.
2. Session / Cookie 방식
사용자의 정보를 저장하고 열쇠가 되는 세션ID 값을 만들고 쿠키에 보관하는 방식.

❶ 사용자가 로그인을 한다.
❷ 서버에서는 계정정보를 읽어 사용자를 확인한 후, 사용자의 고유한 ID값을 부여하여 세션 저장소에 저장한 후, 이와 연결되는 세션ID를 발행합니다.
❸ 사용자는 서버에서 해당 세션ID를 받아 쿠키에 저장을 한 후, 인증이 필요한 요청마다 쿠키를 헤더에 실어 보냅니다.
➍ 서버에서는 쿠키를 받아 세션 저장소에서 대조를 한 후 대응되는 정보를 가져옵니다.
➎ 인증이 완료되고 서버는 사용자에 맞는 데이터를 보내줍니다.
(장점)
- 쿠키가 담긴 HTTP 요청이 도중에 노출되더라도 쿠키 자체(세션 ID)는 유의미한 값을 갖고 있지 않음.
- 고유의 ID값을 발급받기 때문에 서버에서는 쿠키 값을 받았을 때 일일이 회원정보를 확인할 필요 없음.
(단점)
- 보안에 취약함. 만일 A 사용자의 HTTP 요청을 B 사용자(해커)가 가로챘다면 그 안에 들어있는 쿠키도 훔칠 수 있음. 그리고 B 사용자는 훔친 쿠키를 이용해 HTTP 요청을 보내면 서버의 세션저장소에서는 A 사용자로 오인해 정보를 잘못 보여줌(세션 하이재킹 공격).
- 서버에서 세션 저장소를 사용하기 때문에 추가적인 저장공간을 필요로 하게되고 부하도 높아짐.
3. 토큰 기반 인증 방식 (JWT)
인증의 대표 주자. JWT는 Json Web Token의 약자로(외국에서 ‘JOT’으로 읽는다네요 호호) 인증에 필요한 정보들을 암호화시킨 토큰을 뜻함. 위의 세션/쿠키 방식과 유사하게 사용자는 Access Token(JWT 토큰)을 HTTP 헤더에 실어 서버로 보냄.

❶ 사용자가 로그인을 한다.
❷ 서버에서는 계정정보를 읽어 사용자를 확인 후, 사용자의 고유한 ID값을 부여한 후, 기타 정보와 함께 Payload에 넣습니다.
❸ JWT 토큰의 유효기간을 설정합니다.
➍ 암호화할 SECRET KEY를 이용해 ACCESS TOKEN을 발급합니다.
➎ 사용자는 Access Token을 받아 저장한 후, 인증이 필요한 요청마다 토큰을 헤더에 실어 보냅니다.
➏ 서버에서는 해당 토큰의 Verify Signature를 SECRET KEY로 복호화한 후, 조작 여부, 유효기간을 확인합니다.
➐ 검증이 완료되면, Payload를 디코딩하여 사용자의 ID에 맞는 데이터를 가져옵니다.
(장점)
- 세션/쿠키는 별도의 저장소의 관리가 필요한 반면 JWT는 발급한 후 검증만 하면 되기 때문에 추가 저장소가 필요 없음(Stateless).
- 확장성이 뛰어남. 토큰 기반으로 하는 다른 인증 시스템에 접근 가능.
(단점)
- 특정한 규칙에 의해 복호화되는 것이니 규칙이 알려지면 해킹 가능. 실제로 대규모 데이터가 있다면 해석이 됨(rainbow table).
- 세션/쿠키 방식에 비해 JWT의 길이가 길어짐. 인증이 필요한 요청이 많아질 수록 서버의 자원낭비 발생.
- 세션/쿠키의 경우 만일 쿠키가 악의적으로 이용될 때, 해당하는 세션을 지우면 되지만 JWT는 한 번 발급되면 유효기간이 완료될 때 까지 돌이킬 수 없음.
4. access token과 refresh token
Refresh Token은 Access Token과 똑같은 JWT 형태. 최초 로그인 시 Access Token과 동시에 발급되는 Refresh Token은 긴 유효기간을 가지면서, Access Token이 만료됐을 때 새로 발급해주는 열쇠가 됨.

❶ 사용자가 ID , PW를 통해 로그인합니다.
❷ 서버에서는 회원 DB에서 값을 비교합니다(보통 PW는 일반적으로 암호화해서 들어감).
❸ ~ ➍ 로그인이 완료되면 Access Token, Refresh Token을 발급합니다. 이때 일반적으로 회원DB에 Refresh Token을 저장해둡니다.
➎ 사용자는 Refresh Token은 안전한 저장소에 저장 후, Access Token을 헤더에 실어 요청을 보냅니다.
➏ ~ ➐ Access Token을 검증하여 이에 맞는 데이터를 보냅니다.
➑ 시간이 지나 Access Token이 만료됐다고 보겠습니다.
➒ 사용자는 이전과 동일하게 Access Token을 헤더에 실어 요청을 보냅니다.
❿ ~ ⓫ 서버는 Access Token이 만료됨을 확인하고 권한없음을 신호로 보냅니다.
* Access Token 만료가 될 때마다 계속 과정 9~11을 거칠 필요는 없습니다.
* 사용자(프론트엔드)에서 Access Token의 Payload를 통해 유효기간을 알 수 있습니다. 따라서 프론트엔드 단에서 API 요청 전에 토큰이 만료됐다면 바로 재발급 요청을 할 수도 있습니다.
⓬ 사용자는 Refresh Token과 Access Token을 함께 서버로 보냅니다.
⓭ 서버는 받은 Access Token이 조작되지 않았는지 확인한후, Refresh Token과 사용자의 DB에 저장되어 있던 Refresh Token을 비교합니다. Token이 동일하고 유효기간도 지나지 않았다면 새로운 Access Token을 발급해줍니다.
⓮ 서버는 새로운 Access Token을 헤더에 실어 다시 API 요청을 진행합니다.
(장점)
- 기존의 Access Token만 있을 때보다 안전함.
(단점)
- 구현이 복잡함.
- Access Token이 만료될 때마다 새롭게 발급하는 과정에서 생기는 HTTP 요청 횟수가 많음(서버 자원 낭비).
* 어떤 정보를 클라, 서버에 넣을건지 구별해야함. 클라이언트 한명만 보는건 클라이언트(ex. 로그인 과정 중에 발급된 key 값), 우리 서비스에 모든 사용자가 봐야하는 건 서버에(ex. 게시판 정보, 로그인 정보).
* 자주 사용되는 것, 사용되지 않는 것에 대한건 최적화의 영역임.
추가 학습
로그인 기능 구현하기
📑 결과보기

npm
- Node Packaged Manager
- 앱스토어처럼 node.js로 만들어진 package를 관리해주는 도구.
- npm으로 firebase-tools를 설치할 수 있음.

파이어베이스 설치

구현 과정
- 회원가입 폼을 작성했을 때 firebase에 정보 저장하기 👉 참고자료
1. 자바스크립트 프로젝트에 Firebase를 추가.
2. 신규 사용자의 이메일 주소와 비밀번호를
createUserWithEmailAndPassword
에 전달하여 신규 계정을 생성. 3. submit 이벤트가 발동했을 때 실행.

- 회원가입 후 로그인 된 nav로 바꾸기 👉 Firebase에서 사용자 관리하기
1.
currentUser
속성을 사용하여 현재 로그인한 사용자를 가져올 수 있음. 사용자가 로그인 상태가 아니라면 currentUser 값이 null. 2. if else 문을 이용하여 로그인 상태라면 innerHTML을 loggedNavHTML로 변경함.
- 비밀번호 기반 로그인, 로그아웃 만들기 👉 자바스크립트를 사용하여 비밀번호 기반 계정으로 Firebase에 인증하기
1. 신규 사용자가 가입 양식을 사용해 가입하고 나면 필요에 따라 앱에서 계정 유효성 검사 절차를 완료함.
2. 신규 사용자의 이메일 주소와 비밀번호를
createUserWithEmailAndPassword
에 전달하여 신규 계정을 생성. 3. 사용자가 앱에 로그인하면 다음과 같이 사용자의 이메일 주소와 비밀번호를signInWithEmailAndPassword
에 전달. 4. 사용자를 로그아웃시키려면signOut
을 호출.
소셜(구글) 로그인 구현
.gif?table=block&id=6385b25b-2c19-4d75-a5f2-dbe5a5230fc7&cache=v2)
- Google 제공업체 객체의 인스턴스를 생성.
- Google 제공업체 객체를 사용해
signInWithPopup
로 Firebase에 인증.
버블링과 캡처링

- 버블링 - 이벤트가 제일 깊은 곳에 있는 요소에서 시작해 부모 요소를 거슬러 올라가며 발생.
- 캡처링 - window 로부터 이벤트가 발생한 요소까지 이벤트를 전파.
- addeventListener에서 마지막 인자에 boolean 값으로 선택할 수 있음.
event.target
- 이벤트가 발생한 가장 안쪽의 요소는 타깃(target) 요소라고 불리고, event.target을 사용해 접근할 수 있음.
- event.target은 실제 이벤트가 시작된 ‘타깃’ 요소. 버블링이 진행되어도 변하지 않음.
- event.currentTarget은 ‘현재’ 요소로, 현재 실행 중인 핸들러가 할당된 요소를 참조함.
마치며
인생 처음으로 로그인 기능을 구현했다. 물론 firebase를 사용해 간단하게 만든거지만 너무 뿌듯하다. 로그인 했다 로그아웃 했다만 몇십번 한 것 같다. 기분이 좋다.
🤔 어려웠던 점
- event 등록이 어려웠다. 왜냐하면 JS로 DOM 객체를 동적으로 지우고 생성하는 과정에서 event가 등록된 DOM 객체가 사라졌기 때문이다. → 사라지지 않는 container 객체에 event를 걸고 event 버블링을 이용해, 동적으로 생기는 하위요소에 영향을 받지 않게 하자.
- innerHTML로 DOM 객체를 만들었을 때, querySelector 타이밍을 잡지 못해 객체가 생성되기 전에 가져와서 null에 event를 적용했다. → DOM 객체가 생성된 이후에 querySelector로 가져오자.
- firebase를 처음 사용했는데 많이 어려웠다. 유튜브에서 튜토리얼 영상을 찾아보고 공식 문서를 확인하며 코드를 작성하였다.
같은 class를 사용할 땐 querySelector가 가장 먼저 있는 것을 불러오기 때문에 document가 아닌 불러와야하는 DOM 객체를 선택해야 함.
🤔 궁금한 점
- firebase에서 인증되지 않는 도메인(to vscode 라이브 서버, aws 호스팅 주소)이라 뜰 경우
- [FOUC : Flash of Unstyled Content] HTML이 다시 그려질 때 깜빡임 문제 (CSS에서 깜빡임이 있는동안 display:none으로 설정 후 로딩바를 넣는 방법이 괜찮은지) → 스켈레톤 이미지는 남기고 내용만 바꾸는 형식도 좋음.