스파르타 코딩클럽 리액트 강의 [심화] notetaking (작성중)

너겟·2022년 6월 6일
0

Learning_React

목록 보기
8/9
post-thumbnail

1주차

Javascript Re-start! (1) - 기본

변수와 상수

변수 생성 3단계

  • 선언: 실행 컨텍스트에 변수 객체를 등록 (스코프가 참조하는 대상이 되도록)
  • 초기화: 변수 객체에 등록된 변수를 위해 메모리에 공간을 확보 (여기서 변수는 보통 undefined로 초기화된다.)
  • 할당: undefined로 초기화된 변수에 실제 값을 할당

var, let, const

  • var: 요즘 잘 안씀.
  • let: block-scope를 갖는다. 재선언은 불가, 재할당은 가능
// 재할당은 가능!
let cat_name = 'perl';
cat_name = '펄이';

// 재선언은 오류!
let cat_name = 'perl';
let cat_name = '펄이'; 
  • const: block-scope를 갖는다. 재선언 불가, 재할당도 불가

TDZ(Temporal Dead Zone) = 일시적 사각지대

var과 let, const의 차이점 중 하나는 변수가 선언되기 전에 호출하면 ReferenceError가 난다는 점이다.호이스팅(=선언 끌어 올리기)은 된다. 다만, 선언한 후, 초기화 단계에서 메모리에 공간을 확보하는데, 선언을 호이스팅해도 초기화 전까지 메모리에 공간이 없죠! 그래서 변수를 참조할 수 없기 때문

Strict mode

'use strict;'를 스크립트 최상단에 써주면 모던 자바스크립트에서 지원하는 모든 기능을 활성화해준다.

Javascript Re-start! (2) - 객체

  • {...} ← 중괄호 안에 여러 쌍의 프로퍼티를 넣을 수 있다.
    - 프로퍼티는 key : value로 구성
    ```jsx
    // 객체 생성자로 만들기
    let cat = new Object();

// 객체 리터럴로 만들기
// 중괄호로 객체를 선언하는 걸 리터럴이라고 하는데, 객체 선언할 때 주로 씁니다!
let cat = {};

const로 선언된 객체는 수정이 가능 (객체의 프로퍼티는 보호되지 않는다!)
    
    
## Javascript Re-start! (3) - 함수    

- 자바스크립트는 ()가 있으면 함수를 실행하고 ()가 없으면 함수를 문자형으로 바꿔 출력한다.
- 함수는 기본적으로 undefined를 반환 (return을 쓰지 않으면)

#### 함수 선언문과 함수 표현식
함수 선언문
함수 선언문으로 선언을 하면 독립적 구문으로 존재해서 차례대로 선언을 안해도 어딘가에 저장이 되어있다. (코드 블록이 실행되기 전에 미리 처리되어 블록 내 어디서든 사용할 수 있다.)
```jsx
// 이렇게 생긴 게 함수 선언문 방식으로 함수를 만든 거예요.
function cat() {
	console.log('perl');
}

함수 표현식
함수 표현식으로 함수를 생성하면 함수가 표현식의 일부로 존재. 선언을 해주고 나서부터 사용이 가능.

// 이렇게 생긴 게 함수 표현식을 사용해 함수를 만든 거예요.
let cat = function() {
	console.log('perl');	
}

// 물논 화살표 함수로 써도 됩니다.
// 다만 주의하실 점! 화살표 함수는 함수 표현식의 단축형이라는 거! 주의하세요! :) 
let cat2 = () => {
	console.log('perl2');
}

지역 변수와 외부 변수

  • 지역 변수
    • 함수 내에서 선언한 변수
    • 함수 내에서만 접근 가능
  • 외부 변수(global 변수라고도 합니다.)
    • 함수 외부에서 선언한 변수
    • 함수 내에서도 접근할 수 있다.
    • 함수 내부에 같은 이름을 가진 지역 변수가 있으면 사용할 수 없다.

DOM (Document Object Model)

웹페이지는 document고, document는 객체이다.
DOM은 웹페이지의 모든 콘텐츠를 객체로 나타내고 이 객체는 수정할 수 있다. -> document 객체를 사용해 웹 페이지 내의 무엇이든 변경할 수 있다는 이야기

BOM (Browser Object Model)

BOM은 호스트인 브라우저가 제공하는 추가 객체를 뜻함.
navigator, location외에도 confirm, alert 등이 BOM의 일부로 confirm, alert등은 사용자와 브라우저 사이의 원활한 소통을 도와주는 순수한 브라우저 메서드이다.

CRA로 첫 리액트 프로젝트 세팅하기

CRA: react create app

  • (1) nvm으로 node 설정하기
    nvm -v # nvm이 잘 설치되었나 보기 위해, 버전 정보를 확인해봅니다.
    nvm install 16.14.0 # 현재 LTS 버전으로 설치해봅시다!
    nvm use 16.14.0 # 설치한 노드를 사용해봅시다.
  • (2) node로 yarn 설치하기
    node -v # node 버전을 확인해봅니다.
    npm -v # npm은 노드의 패키지 매니저예요. 이걸 통해서 누군가 만들어 둔 패키지를 설치하고 사용할 수 있어요!
    npm install -g yarn # -g는 글로벌로 설치하겠다!고 알려주는 옵션입니다. yarn을 글로벌로 설치해봅시다!
  • (3) yarn으로 create-react-app 설치하기
    yarn -v # yarn 버전을 확인해봅니다.
    # global은 글로벌 설치 옵션입니다. 
    # yarn은 npm과 명령어가 조금 다른데요, install 대신 add를 씁니다.
    # 이런 명령어의 차이는 공식문서를 통해 확인해도 좋고, yarn --help로 확인해도 좋습니다.
    # yarn으로 create-react-app을 설치합니다.
    yarn add create-react-app global 
  • (4) create-react-app으로 프로젝트 만들기
    yarn create react-app firstprj # 첫번째 프로젝트를 만들어봅시다!

CRA없이! 리액트 프로젝트 세팅하기

CRA를 사용하지 않는 이유는 뭘까?

CRA를 사용하면 편하지만 자동으로 생성해주는 파일 중 사용하지 않는 것들도 많다. 조금 더 능동적인 개발환경을 만들기 위해 연습해보는 것.

webpack

bundler (번들러)
번들러는 여러 개로 나뉜 모듈을 하나로 묶어주는 것

babel (compiler)

자바스크립트의 버전과 상관없이 해당 브라우저가 지원하는 버전으로 번역해 주는 것.

컴포넌트가 돔에 그려지려면?

  • ReactDOM.createRoot()
    - pubilc/index.html을 열고 <div id="root"></div>를 찾아봅시다.
    - 이걸 루트 DOM 노드라고 불러요.
    - 우리가 만든 모든 컴포넌트는 이곳에 들어가게 될 겁니다.
    !주의! 물론 예외가 있습니다. 나중에 다뤄볼 Portal인데요, Portal을 사용할 부분을 제외한 모든 컴포넌트는 루트 돔 노드에 들어갈거예요.

  • rc/index.js를 열고 루트를 어떻게 만드는 지 확인해봅시다.

    • const root = ReactDOM.createRoot(document.getElementById('root'));

react element를 진짜 DOM에 올려주는 역할을 하는데 render이다. (루트 돔 노드에 리액트 엘리먼트를 전달하는 역할)
엘리먼트에 변화가 필요할 경우 필요한 부분만 업데이트 해주는 역할도 함

2주차

Hook (함수형)

Hook이란?

  • 오직 함수형 컴포넌트에서만 쓸 수 있다.
  • 컴포넌트의 최상위에서만 호출할 수 있다. (반복문, 중첩문 내에서는 호출할 수 없다. -> 훅의 실행 순서를 늘 동일하게 보장하지 못함)

useState()

useState()는 값을 넣어두고 참조하기 위한 변수(state 변수), 값을 바꿔주기 위한 함수(변경함수)를 반환한다.

const [someValue, setValue] = useState("hi!");

구조 분해 할당이라고 한다. -> 배열이나 객체의 속성을 해체해서 각각의 값을 개별 변수에 할당하게 해주는 것.

useEffect()

useEffect(() => {
  if(is_loaded){
    window.alert("hi! im ready! ٩(๑•̀o•́๑)و");
  }
  return () => {
    window.alert("bye!");
  }
}, [is_loaded]);
  • 위에서 사용한 useEffect의 인자는 2개 입니다.
    • 첫번째 인자는 컴포넌트가 화면에 그려질 때(처음 그려질 때와 수정되어 다시 그려질 때 모두!) 실행할 함수예요.
    • 두번째 인자는 디펜던시 어레이라고 불러요. 의존성 배열입니다.
      배열에 넣은 어떤 값이 변했을 때 useEffect에 넘긴 첫번째 인자를 다시 실행합니다. 그러니까 이 안에다가 state 변경함수를 넣으면, 변경될때마다 실행이 될 것.
  • return () ⇒ {} 부분을 clean up할때 쓴다.

useCallBack()

useEffect와 비슷해보이지만 다르다.

  • 메모리에 저장해두고 두고두고 써먹는 메모이제이션이 가능하다.
  • 리렌더링 될때 컴포넌트 안에 선언해둔 함수 등을 다시 한번 생성하게 되는데, 콜백을 사용하면 여러번 다시 만들지 않아도 된다.
  • 자식 컴포넌트에게 전달해주는 콜백 함수를 메모이제이션할 때 주로 쓴다. -> props로 넘기는 콜백함수를 감싼다.
const myNewFunction = useCallback(() => {
 console.log("hey!", need_update);
}, [need_update]);

useRef()

  • 원본이 아니라 똑같이 생긴 다른 값이라 변경이 된다. (레퍼런스를 가져오는 개념)
  • useState와 다르게 변경해도 리렌더링이 발생하지 않는다.
  • input 등 화면에 이미 노출된 것을 관리할 때 사용한다.
const myNewFunction = useCallback(() => {
 console.log("hey!", need_update);
}, [need_update]);

자바스크립트와 동기성

자바스크립트는 싱글 쓰레드 > 이벤트 루프를 이용해서 비동기 작업을 한다.

  • event queue : 테스크 큐(Task queue)나 콜백 큐(callback queue)라고도 해요. 비동기 처리 함수의 콜백 함수, 비동기식 이벤트 핸들러, 타이머의 콜백 함수를 넣어두는 큐
  • event loop : 테스크(일거리)가 들어오길 기다렸다가 테스크가 들어오면 일을 하고, 일이 없으면 잠깐 쉬기를 반복하는 자바스크립트 내의 루프

Prommise

  • 동기와 비동기
  • 콜백: 특정 함수에 매개변수로 전달된 함수
  • 콜백헬: 비동기 처리가 계속 늘어나면 호출이 중첩되고 관리가 어려워지는 현상.
    콜백 함수 내에서 또 다른 비동기 작업이 필요할 경우 중첩이 발생한다.
function async1('a', function (err, async2){
	if(err){
		errHandler(err);
	}else{
		...
		async2('b', function (err, async3){
			...
		}){
			...
		}
	}
});

Prommise의 생성
비동기 작업을 수행할 콜백 함수를 인자로 전달받아서 사용한다.
생성자 함수로 생성 (new)

// 프라미스 객체를 만듭니다. 
// 인자로는 (resolve, reject) => {} 이런 excutor 실행자(혹은 실행 함수라고 불러요.)를 받아요.
// 이 실행자는 비동기 작업이 끝나면 바로 두 가지 콜백 중 하나를 실행합니다.
// resolve: 작업이 성공한 경우 호출할 콜백
// reject: 작업이 실패한 경우 호출할 콜백
const promise = new Promise((resolve, reject) => {
	if(...){
		...
		resolve("성공!");
	}else{
		...
		reject("실패!");
	}
});

Prommise의 후속 처리 메서드

프라미스로 구현된 비동기 함수는 프라미스 객체를 반환: 비동기 처리 결과(성공 결과나 에러메시지)를 받아서 처리하는데,

1. .then

then의 첫 인자는 성공 시 실행, 두번째 인자는 실패 시 실행됩니다. (첫 번째 인자만 넣어도 된다.)

// 프라미스를 하나 만들어 봅시다!
let promise = new Promise((resolve, reject) => {
	setTimeout(() => resolve("완료!"), 1000);
});

// resolve
promise.then(result => {
	console.log(result); // 완료!가 콘솔에 찍힐거예요.
}, error => {
	console.log(error); // 실행되지 않습니다.
});

.catch

.then의 두번째와 같음. 실패시

// 프라미스를 하나 만들어 봅시다!
let promise = new Promise((resolve, reject) => {
	setTimeout(() => reject(new Error("오류!"), 1000);
});

promise.catch((error) => {console.log(error};);

promise chaining(프라미스 체이닝)

후속처리 체이닝을 넣어서 여러개의 프라미스를 연결할 수 있는데, 이걸로 콜백 헬을 해결할 수 있다.
쉽게 말해, .then을 계속 뒤에 이어주는거다. 그러면 앞에 있는 프라미스가 성공 해야 다음으로 넘어가기 때문.

new Promise((resolve, reject) => {
	setTimeout(() => resolve("promise 1"), 1000);
}).then((result) => { // 후속 처리 메서드 하나를 쓰고,
	console.log(result); // promise 1
	return new Promise(...);
}).then((result) => { // 이렇게 연달아 then을 써서 이어주는 거예요.
	console.log(result);
	return new Promise(...);
}).then(...);

외부 api연결할때 많이 쓰게될 것!

async, await

프라미스 사용( 특히 후속처리)을 엄청 편하게 만들어준다! -> 나중에 제네레이터라는 함수와 이터러블에 대해 따로 다뤄보자!

async

항상 프라미스를 반환하는데, 프라미스가 아닌 값이라도, 프라미스로 감싸서 반환해준다.

// async는 function 앞에 써줍니다.
async function myFunc() {
	return "프라미스를 반환해요!"; // 프라미스가 아닌 걸 반환해볼게요!
}

myFunc().then(result => {console.log(result)}); // 콘솔로 확인해봅시다!

await

async의 짝꿍. await는 프라미스가 처리될 때까지 기다렸다가 그 이후에 결과를 반환.
await를 만나면, 실행이 잠시 중단되었다가 프라미스 처리 후에 실행을 재개

async는 혼자 쓸 수 있지만 await는 혼자 못씀!!

상태관리

  • ContextAPI()
  • Redux
  • Recoil
  • zustand
  • react-query
  • mobx

Redux Tool Kit

툴 킷을 쓰게 되면 액션타입, 액션 생성함수, 리듀서, 기초값을 한 번에 묶어서 사용할 수 있다! → 보일러 플레이트가 많이 줄어든다.

기존의 구조와 비교해보자.

기존 store

import {createStore, combineReducers} from "redux";
import cat from "./modules/cat"

const rootReducer = combineReducers({cat});

const store = createStore(rootReducer);

export default store;

툴킷 store

import {configureStore} from "@reduxjs/toolkit";
import catReducer from "./modules/catSlice"

const store = configureStore( {
  reducer:{
  cat:catReducer,
} } );

export default store;

index.js -> 동일

기존 cat.js

const CHANGE_NAME = "cat/CHANGE_NAME";

const initial_state = {name: "펄이", age: 5}

export const changeName = (name) => {
  return {type: CHANGE_NAME, name: name};
}

export default function reducer(state = initial_state, action={}) {
  switch (action.type) {
    case "cat/CHANGE_NAME": {
      return {...state, name: action.name}
    }

    default :
      return state;
  }
} 

state의 불변성을 위해 스프레드 문법(...)을 써서 새로운 객체를 만들어야 했다.
하지만 툴킷에서는 바로 써도 된다. 왜냐하면 immer이라는 불변성 유지 패키지를 가지고 있기 때문이다. (자바스크립트의 프록시 개체를 이용해서 불변성 유지함)

이걸 툴킷 slice로 만들어보자
catSlice.js

import {createSlice} from "@reduxjs/toolkit";

const catSlice = createSlice( {
  name: 'cat',
  initialState: {
    name: '펄이',
    age: 5,
  },
  reducers: {
    changeName: (state, action)=>{
      state.name = action.payload 
    }
  }
})

export const {changeName} = catSlice.actions;
export default catSlice.reducer;

catSlice안에 action이름과 reducer를 한번에 선언해준다.

실제로 컴포넌트 내에서 쓰는 방식을 이전과 같은데 다른 점은 기존 리덕스보다 액션 개체와 리듀서 만드는 방식이 조금 수월해졌다는 것.

그리고 라이브러리를 많이 가지고 있음 (immer 같은 것도 따로 안깔아도 가지고 있음)

라우팅

v6 버전으로 진행한다.

v5 -> v6 바뀐것들
switch -> routes
component -> element
history.push -> useNavigate, Link

공식문서

import ReactDOM from "react-dom/client";
import {
  BrowserRouter,
  Routes,
  Route,
} from "react-router-dom";
// import your route components too

const root = ReactDOM.createRoot(
  document.getElementById("root")
);
root.render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />}>
        <Route index element={<Home />} />
        <Route path="teams" element={<Teams />}>
          <Route path=":teamId" element={<Team />} />
          <Route path="new" element={<NewTeamForm />} />
          <Route index element={<LeagueStandings />} />
        </Route>
      </Route>
    </Routes>
  </BrowserRouter>
);
import { useNavigate } from "react-router-dom";

function Invoices() {
  let navigate = useNavigate();
  return (
    <div>
      <NewInvoiceForm
        onSubmit={async (event) => {
          let newInvoice = await createInvoice(
            event.target
          );
          navigate(`/invoices/${newInvoice.id}`);
        }}
      />
    </div>
  );
}

라우터 예제는 prac 폴더에서 진행했다.

3주차

Mock API (postman) 와 form 을 다뤄보자.
키워드: 네트워크 요청, http 프로토콜, 웹 저장소, 인증

Mock API

REST API (Representational State Transfer API)

서버와 클라이언트 사이 통신 방식 중 하나

RESTful -> REST API를 제공하는 웹서비스

  • REST 구성
    • 자원: URI
    • 행위: Http method (GET, POST, PUT, DELETE)
    • 표현: JSON, XML, ... (대부분의 경우 JSON을 주고 받습니다.)

네트워크 요청 1 - XMLHTTPRequest

브라우저는 XMLHttpRequest를 이용해서 Ajax요청을 생성하고 전송. XML뿐 아니라 JSON, text 등등 모든 종류의 데이터를 받아올 수 있고 HTTP이외의 프로토콜도 지원한다. (file, ftp도 지원)
공식문서

  1. onreadystatechangec
    readyState에 따라 다른 번호를 표시함:
  • XMLHttpRequest.open() 메소드 호출 이전
  • OPENED = 1; // XMLHttpRequest.open() 메소드 호출 완료
  • HEADERS_RECEIVED = 2; // XMLHttpRequest.send() 메소드 호출 완료
  • LOADING = 3; // 응답 기다리는 중(서버 응답 중(XMLHttpRequest.responseText 미완성 상태))
  • DONE = 4; // 서버 응답 완료
  1. onload
    load 이벤트는 서버 응답이 완료된 경우
// 두가지 방법으로 응답을 받을 수 있어요! 하나는 onreadystatechange를 쓰는 방법,
// 다른 하나는 onload를 쓰는 방법입니다.

// 1. 
// XMLHttpRequest.readyState 프로퍼티가 변경(이벤트 발생)될 때마다 
// 콜백함수(이벤트 핸들러)를 호출해요!
xhr.onreadystatechange = function (e) {
  // 이 함수는 Response가 클라이언트에 도달하면 호출됩니다!

  // readyStates는 XMLHttpRequest의 상태(state)를 반환해요
  // readyState :::
  // UNSENT = 0; // XMLHttpRequest.open() 메소드 호출 이전
	// OPENED = 1; // XMLHttpRequest.open() 메소드 호출 완료
	// HEADERS_RECEIVED = 2; // XMLHttpRequest.send() 메소드 호출 완료
	// LOADING = 3; // 응답 기다리는 중(서버 응답 중(XMLHttpRequest.responseText 미완성 상태))
  // DONE = 4; // 서버 응답 완료
  if (xhr.readyState !== XMLHttpRequest.DONE) return;

  // status는 response 상태 코드를 반환 : 200 => 정상 응답
  if(xhr.status === 200) {
    console.log(xhr.responseText);
  } else {
    console.log('Error!');
  }
};

//2. 
// load 이벤트는 서버 응답이 완료된 경우에 발생해요!
xhr.onload = function (e) {
  // status는 response 상태 코드를 반환 : 200 => 정상 응답
  if(xhr.status === 200) {
    console.log(xhr.responseText);
  } else {
    console.log('Error!');
  }
};

오래된 방식이고 요즘은 잘 안씀

네트워크 요청 2 - Fetch API와 Axios

XMLHttpRequest보다 훨씬 사용법이 간단하고 서비스 워커 등 다른 기술을 쓸 때 손쉽게 엮어 사용할 수 있음!

fetch()를 호출하면?
브라우저는 네트워크 요청을 보내고 프라미스를 반환됩니다.
이 프라미스를 사용해서 fetch()를 호출!

단! fetch()는 구식 브라우저에서는 돌아가지 않음

Fetch API

get

// url – 접근하고자 하는 URL
// options – 선택 매개변수, method나 header 등이 여기에 들어가요!
let promise = fetch(url, [options])
``` = fetch(url, [options])

```jsx
const response = fetch("http://localhost:5001/sleep_times");

뒤에 options를 추가하지 않고 그냥 url만 입력하면 get 요청을 보내고 promise를 반환함

post

const callSomething = async () => {
	let data = {
      "id": 6,
      "day": "일", 
			"sleep_time": "10:00"
    },
	let response = await fetch('http://localhost:5001/sleep_times', {
	  method: 'POST',
	  headers: {
	    'Content-Type': 'application/json;charset=utf-8'
	  },
	  body: JSON.stringify(data)
	});
		console.log(response);
}

Axios

공식문서
json으로 알아서 바꿔줌! 편하다 ㅠㅠ

get

config로 GET

axios({
  method: 'get',
  url: 'http://localhost:5001/sleep_times',
})
  .then((response) => {
			console.log(response);
  });

요청 메서드로 GET

axios.get("http://localhost:5001/sleep_times");

post

let data = {
	id: 6,
	day: "일", 
	sleep_time: "10:00"
};

axios.post("http://localhost:5001/sleep_times", data);

명령어 등록하기

package.json에서 이런식으로 등록해놓으면 터미널에서 쉽게 쓸수있다.

"scripts" : {
"server-start": "json-server --watch db.json --port 5001"
}

Polling과 long polling

http요청은 한번 보내고 응답을 받으면 그 요청은 거기서 끝!
왜? http의 비연결성 때문. -> persistent connection 이 불가능

바뀐 데이터가 있을 때 그걸 받아오기 위한 기법이 폴링이다.

폴링

  • 브라우저가 일정 주기를 두고 요청을 보내는 것
  • 실시간으로 바뀐 데이터를 받아올 수 없다.

롱 폴링

  • 요청을 보내고 응답을 지연시키는 것
  • 요청을 보내고 서버가 그 응답을 바로 보내지 않는 것 (서버측에서 접속을 열어두는 시간을 길게 한다.)
  • 데이터 변동이 있다면 바로 응답을 보낸다. 하지만 변동이 없다면 서버는 응답을 일정 시간동안 지연.

폴링의 문제점:

  • 폴링 주기가 짧으면 서버의 성능에 부담이 간다
  • 주기가 길면 실시간성이 떨어진다

토큰 기반 인증

토큰 기반 인증

예전에 세선기반 인증을 쓸때:

  • 사용자의 로그인 상태를 서버가 전부 가지고
  • 서버의 세션에 사용자 정보를 넣고 이 사람이 로그인을 했다 안했다를 전부 기록하고 기억

이 방법의 문제점은 로그인한 사용자가 많아지면 서버에 과부하가 온다 (메모리나 데이터베이스의 한계가 있기 때문)

그래서 요즘은 토큰 기반 인증 방법을 많이 사용
header에 token을 실어서 보냄.

토큰 기반 인증 중 OAuth2.0

외부서비스의 인증 및 권한부여를 관리하는 프레임워크
(Open Authentication, Open Authorization)

기본 동작 방식

  1. 클라이언트서버 사이에 인증(로그인)을 하면 서버가 access_token 을 줍니다.
  2. 클라이언트access_token을 이용해서 API 요청을 할 수 있어요.
  3. 서버는 API 요청을 받고, access_token을 가지고 권한이 있나 없나 확인해서 결과를 클라이언트에 보내줍니다. (토큰은 헤더 안에 실어서 전달)

OAuth 동작 방식 (외부 서비스 엮음 ver.)

구글 로그인을 하는 상황:

자원소요자:
유저의 정보를 가지고 있는 자 (아이디, 비번 뭔지 아는 사람)
Resource Server(자원 서버) :
유저들의 아이디 비번 정보를 다 가지고 있는 서버
Authorization server(권한 서버):
접근 권한을 확인해서 토큰을 발급해주는 서버

  1. 유저가 구글 로그인을 합니다.
    • 자원 소유자가 자원서버에 권한 요청을 한거죠!
  2. 구글은 로그인할 때 유저가 입력한 정보(아이디, 비밀번호 등)을 보고 클라이언트(우리 웹사이트!)에 접근 권한을 줍니다.
  3. 클라이언트는 이 권한을 가지고 Authorization server(권한 서버)access_token을 요청합니다.
  4. 클라이언트는 이 access_token을 가지고 구글에서 유저 정보를 가져올 수 있어요.
  5. 구글클라이언트가 보낸 access_token을 가지고 권한이 있나 없나 확인해서 결과클라이언트에 보내줍니다.

JWT(Json Web Token)

토큰의 한 형식 -> JSON 형태로 이루어져 있는 토큰

구성요소
[header].[payload(내용)].[signature(서명)]

  • header: 토큰 타입과 암호화 방식 정보가 들어간다.
  • payload: 토큰에 담을 정보가 name: value 쌍으로 들어간다.
  • signature: 서명 정보입니다. secret key를 포함해서 header와 payload 정보가 암호화 되어 들어간다.

동작 방법

  • 유저가 로그인 시도,
  • 서버가 요청을 확인하고 secret key를 가지고 access_token을 발급
  • 클라이언트에 JWT를 전달하고
  • 클라이언트는 토큰 보관하고 있다가 API 요청을 할 때 Authorization header에 JWT를 담아서 보냄
  • 서버는 JWT의 서명을 확인하고 payload에서 정보를 확인해서 API 응답을 보냄

웹 저장소

클라이언트가 access_token을 저장해두는 곳

쿠키

쿠키만들기

// key는 MY_COOKIE, value는 here, 
document.cookie = "MY_COOKIE=here;";

쿠키삭제

document.cookie = "MY_COOKIE=here; expires=new Date('2020-12-12').toUTCString()";

세션 스토리지

세션 스토리지에 저장된 데이터는 브라우저를 닫으면 제거

// key는 MY_SESSION, value는 here인 세션을 만들어요.
sessionStorage.setItem("MY_SESSION", "here");

// key값으로 쉽게 가져올 수 있어요 :) 
sessionStorage.getItem("MY_SESSION");


/ 하나만 삭제하고 싶다면, 이렇게 키를 통해 삭제합니다.
sessionStorage.removeItem("MY_SESSION");

// 몽땅 지우고 싶을 땐 clear()를 쓰면 됩니다. :) 
sessionStorage.clear();

로컬 스토리지

쿠키와 마찬가지로 key:value 형태의 저장소. 따로 지워주지 않으면 계속 브라우저에 남아있음!

// key는 MY_LOCAL, value는 here인 데이터를 저장해요.
localStorage.setItem("MY_LOCAL", "here");

// key값으로 쉽게 가져올 수 있어요 :) 
localStorage.getItem("MY_LOCAL");

// 하나만 삭제하고 싶다면, 이렇게 키를 통해 삭제합니다.
localStorage.removeItem("MY_LOCAL");

// 몽땅 지우고 싶을 땐 clear()를 쓰면 됩니다. :) 
localStorage.clear();

토큰은 어디에 저장?

어디에 저장해도 상관은 없지만, 로컬 스토리지의 경우 보안상 취약하기 때문에 프로젝트의 성향에 따라 그때그때 다르게 설정해준다.

인증처리 - 1. Firebase Authentication

firebase auth

4주차

5주차

profile
꾸준하게 하는 법을 배우는 중입니다!

0개의 댓글