210407 ~ 11_TIL / 토큰

김승훈·2021년 5월 4일
1

flow-clone_TIL

목록 보기
12/12

7일

  1. modal 작업,
  2. login api 호출 후 토큰 받아오기

8일 , 9일

.... 로그인 삽질

로그인 삽질하면서

요청 헤더

Authorization : 인증 토큰을 서버로 보낼 때 쓰이는 헤더

Cookie : 쿠기 값 key-value로 표현된다. ex) attr1=value1; attr2=value2

https://jeong-pro.tistory.com/181

https://mangkyu.tistory.com/55

https://dooopark.tistory.com/6

토큰

https://velopert.com/2350

1. 토큰은 왜 사용할까?

우선, 가장 큰 이유는 HTTP의 특성때문입니다. HTTP는 연결 지향 프로토콜TCP 기반임에도 불구하고, 대표적인 비연결 지향 프로토콜입니다. 따라서 한 번의 요청-응답 사이클이 완료되면 연결을 종료하기 때문에, 동일한 클라이언트가 요청을 아무리 많이 하더라도 프로토콜은 모두 처음보는 것 마냥 인지합니다! 이를 stateless 하다고 표현하기도 합니다.

stateful해지기 위해서, 즉, 상태를 유지하기 위해 많은 시도들이 있었습니다. 예를 들면, 우리가 잘 아는 세션이나 쿠키가 있습니다. 이는 대표적인 서버 기반 인증 시스템입니다. 이 시스템은 인증에 필요한 특정 유저 정보를 서버 혹은 데이터베이스에 저장할 수밖에 없습니다. 따라서, 서버나 데이터베이스의 부담이 증가하겠죠? 😥 또한, CORS (Cross-Origin Resource Sharing)의 문제도 존재합니다. 웹 어플리케이션에서 세션을 관리 할 때 자주 사용되는 쿠키는 단일 도메인 및 서브 도메인에서만 작동하도록 설계되어있습니다. 따라서 쿠키를 여러 도메인에서 관리하는것은 좀 번거롭습니다.

그러나 토큰 기반 인증 시스템은 stateless 합니다. 무상태. 즉 상태유지를 하지 않는다는 것이죠. 이 시스템에서는 더 이상 유저의 인증 정보를 서버나 세션에 담아두지 않습니다. 서버의 부담이 감소할뿐만 아니라 보안성도 높고, 여러 플랫폼 및 도메인에서 적용가능하다는 장점이 있습니다! 또한, 대표적인 토큰 기반 인증 시스템인 JWT는 웹 표준으로서, 많이 이용되고 있습니다.

2. 토큰은 어디에 담아야할까?

우리는 토큰이 유저 인증을 위해 아주 효과적인 도구라는 것을 알았습니다. 유저를 인증할 수 있는 어떤 값을 토큰📦에 담겠습니다. 그렇다면! 토큰은 HTTP의 어디에 담아서 전달해야 할까요? 인증 정보는 표준적으로 Authorization header에 담습니다. 그 형태를 자세히 살펴보자면, 다음과 같습니다.

header 내에 Authorization Key의 Value 값으로서 우리는 인증 스키마를 담습니다. 이때, 인증 스키마는 type credential로 이루어지는데요. type은 인증 방식을 의미하며, 대표적으로 Bearer이 있습니다. credential은 인증정보, 즉, 실질적으로 우리가 보내고자 하는 유저의 인증정보입니다. 대표적으로 access token(위 그림의 '2B-LtDr4UURb87K' 부분)의 값이 있겠네요!

type의 더 많은 종류가 궁금했는데, POSTMAN을 참고했을때, 다음과 같은 type이 있는 것 같습니다.

3. 결론

이번에는 토큰 인증 방식이 왜 필요한지, 어떻게 토큰을 통해 인증 정보를 담는지 살펴보았습니다! 무작정 token header를 만들어서 보내곤 했는데, 이번 기회에 표준을 잘지키며 개발할 수 있겠습니다!

참고 자료


10일

  1. 쿠키 없을 시 로그인 페이지 리다이렉트
function loginAPI(data) {
  return axios.post('/login', qs.stringify(data));
}

function* login(action) {
  try {
    const result = yield call(loginAPI, action.data);
    const { token } = result.data;
    yield put({
      type: LOGIN_SUCCESS,
      data: token,
    });
    axios.defaults.headers.common.Authorization = `Bearer ${token}`;
    document.cookie = `token=${token}`;
    document.cookie = `userId=${action.data.username}`;
  } catch (error) {
    console.log(error);
    yield put({
      type: LOGIN_FAILURE,
      error: error.response.data,
    });
  }
}
/*
로그인 api를 호출 후 반환값으로 토큰을 받는다 (로그인 유지를 하고 판별하기 위해 토큰을 쿠키에 저장했다.)

토큰 기반의 인증 시스템은 아래와 같은 과정으로 작동한다.
1. 사용자가 아이디와 비밀번호로 로그인을 한다.
2. 서버 측에서 해당 정보를 검증한다.
3. 정보가 정확하다면 서버 측에서 사용자에게 Signed 토큰을 발급한다. (Signed는 해당 토큰이 서버에서 정상적으로 발급된 토큰임을 증명하는 Signature를 가지고 있다는 것)
4. 클라이언트 측에서 전달받은 토큰을 저장해두고, 서버에 요청을 할 때마다 해당 토큰을 서버에 함께 전달한다. 이때 Http 요청 헤더에 토큰을 포함시킨다. 
ex)  axios.defaults.headers.common.Authorization = `Bearer ${token}`;
5. 서버는 토큰을 검증하고, 요청에 응답한다.
 ////////////
- 유저가 로그인을 하고 서버에 세션을 이용해서 정보를 기록하는대신, Token 을 발급한다.
 - 클라이언트는 발급된 Token 을 저장한다 (일반적으로 local storage 에 저장한다.)
 - 클라이언트는 요청 시 저장된 Token 을 Header 에 포함시켜 보낸다. 
 - 서버는 매 요청시 클라이언트로부터 전달받은 Header 의 Token 정보를 Verification 한 뒤, 해당 유저에 권한을 인가한다.
출처: https://jins-dev.tistory.com/entry/Session-기반-인증과-Token-기반-인증 [Jins' Dev Inside]
*/

11일

  1. 프로젝트 만들기

  2. 프로젝트 리스트 출력

    function loadProjectsAPI() {
      return axios.get('/projects');
    }
    
    function* loadProjects() {
      try {
        const result = yield call(loadProjectsAPI);
        console.log('resultresultresult', result.data);
        yield put({
          type: LOAD_PROJECTS_SUCCESS,
          data: result.data.projectList,
        });
      } catch (error) {
        console.log(error);
        yield put({
          type: LOAD_PROJECTS_FAILURE,
          error,
        });
      }
    }
    /////main.js
    export const getServerSideProps = wrapper.getServerSideProps(async (context) => {
      const { token } = cookies(context);
      const cookie = context.req ? context.req.headers.cookie : '';
      axios.defaults.headers.Cookie = '';
      if (context.req && cookie) {
        axios.defaults.headers.common.Authorization = `Bearer ${token}`;
      }
      context.store.dispatch({
        type: LOAD_PROJECTS_REQUEST,
      });
      context.store.dispatch(END);
      await context.store.sagaTask.toPromise();
    });
    /*
    ssr 이라서 새로고침?  ...  페이지 이동시에 redux state 가 초기화가 된다.
    서버에서 페이지를 불러 올때마다 getServerSideProps: 각각의 요청마다 data를 fetch한다.
    유저인증을 위해 쿠키에 저장한 토큰을 import cookies from 'next-cookies'; 라이브를 사용하여 가져와서 
    headear 에 담아 
    
    context.store.dispatch({
        type: LOAD_PROJECTS_REQUEST,
     });
    하였다 .
    
    */

페이지에서 async호출 된 함수 를 내 보내면 getServerSidePropsNext.js는에서 반환 한 데이터를 사용하여 각 요청에 대해이 페이지를 사전 렌더링합니다 getServerSideProps.

getServerSideProps는 서버에서 실행됩니다. 서버에서 리덕스 스토어가 새로 생성된 후 실행되는 것이라 기존 클라이언트 스테이트에 접근할 수 없습니다.

0개의 댓글