[TIL] 22.12.12 -RefreshToken, Observable

nana·2022년 12월 12일
0

TIL

목록 보기
46/50
post-thumbnail

RefreshToken


RefreshToken 작동원리


refreshToken은 accessToken을 1시간마다 자동으로 인가해준다.

accessToken을 만드는 과정에서 accessToken과 똑같지만, 2주~1개월 정도의 기간을 유지하는 refreshToken을 생성한다.


인증

로컬/세션 스토리지의 경우 보안에 취약하기 때문에 토큰을 취급할 때에는 사용하지 않고, 쿠키에 RefreshToken을 담아서 저장해준다.

accessToken은 payload로 전달, refreshToekn은 브라우저 cookie에 저장
-> 브라우저 cookie에 refreshToken이 자동으로 저장됨
-> accessToken은 변수에 직접 저장

쿠키에 저장하는 이유 - 쿠키의 secure / httpOnly 옵션
쿠키라고 해서 매우 안전한 것은 아니지만, 로컬/세션 스토리지와는 다르게 secure, httpOnly 등의 옵션을 설정할 수 있다.

  • httpOnly : 브라우저에서 Javascript를 이용해 쿠키에 접근할 수 없고, 통신으로만 해당 데이터를 주고받을 수 있다. (javascript로 확인할 수 없음)
  • secure : https 통신 시에만 해당 쿠키를 받아올 수 있다.

인가

fetchUser시 header에 accessToken을 보내고, 성공 / 실패 복호화
-> 1시간이 지나면 토큰 만료


RefreshToken을 이용해 AccessToken을 새로 발급받는 과정

  1. AccessToken 만료 후 인가 요청

  2. 브라우저에서는 토큰 만료로 로그인이 실패했을 때, 에러를 잡는 if문을 작성해서 실행시켜주어야 함

  3. RefreshToken으로 accessToken 재발급 요청 -> 변수에 저장
    쿠키에 있는 refreshToken을 restoreAccessToken API를 통해 백엔드로 보내서 refreshToken 인가를 함
    -> 인가(복호화) 성공 시 새로운 accessToken을 만들어 다시 브라우저로 돌려줌

  4. 브라우저에서 변수에 저장된 accessToken을 새로운 accessToken으로 바꾸어 주어야 함
    (state에 재저장)

  5. 실패 쿼리 재시도 (accessToken값을 변경해서 fetchUser를 다시 시도함)

유저 입장에서는 실패하고 토큰을 재발급 받고, 실패 쿼리를 재시도하는 과정이 보이지 않음
=> 조용한 인증 (SilentAuth)


AuthService / ResourceService

  • AuthService : 인증 과정
  • ResourceService : 인증 후 데이터를 받아오는 과정
    백엔드에서 각 API마다 폴더를 만들어, 한 API에서 에러 발생 시 다른 곳에 영향이 가지 않도록 구현해준다. (MSA)

소셜 로그인 - Open Authentication (OA)
구글 / 네이버 / 카카오 등 자회사의 DB를 바탕으로 AuthService를 제공하며, 사용자가 소셜 로그인을 할 수 있다.


RefreshToken 실습


libraries 폴더로 이동해서 getAccessToken.ts 라는 이름의 파일을 생성한다.

mutation이 안되므로 graphql-request에서 graphqlClient를 import해서 accessToken을 재발급 받는 코드를 별도 함수로 분리하여 입력해준다.

uploadLink의 요청을 보낼때 uri 경로를 http에서 https로 바꾸고, 민감한 정보 포함을 승인한다는 뜻의 credentials: “include” 옵션을 추가해주어야 한다.

만일, credentials: “include” 이 없다면 refreshToken을 쿠키에 못담을 뿐 만아니라 쿠키에 담겨있는것들도 백엔드로 전송이 되지 않는다.

refreshToken을 사용하기 위해서는 graphQL 요청을 보내야 하는데, errorLink를 생성하는 코드는 ApolloProvider 바깥에 있기 때문에 useQuery나 useApolloClient등을 이용해 graphQL 요청을 보낼 수 없다.

이러한 문제를 해결하기 위해서 graphql-request 라이브러리를 설치해준다.


graphql-resquest 설치
yarn add graphql-request


apollosetting 부분에서 에러를 잡아주는 link 작성

import { onError } from "@apollo/client/link/error";
  • graphQLErrors : 에러들을 캐치해준다.
  • operation : 방금전에 실패했던 쿼리가 뭐였는지 알아둔다.
  • forward : 실패했던 쿼리들을 재전송 한다.

ApolloClient link에 errorLink도 연결해준다. 이때, 링크 연결 순서에 따라 적용되니까 순서에 유의!

stores 폴더에 accessToken을 재발급 받는 글로벌 함수를 만들어준다.

 const aaa = useRecoilValueLoadable(restoreAccessTokenLoadable); // api 통합

새로고침 시 토큰을 유지하도록 해준다.

app에 적용된 useEffect에 getAccessToken 함수를 실행하고,
권한분기로 권한이 필요한 페이지에서 새로고침 시 getAccessToken이 두 번 실행되서 비효율적이다.
-> 두개를 그룹핑해서 사용해준다.
-> recoil에 있는 setAccessToken state 재사용


Observable


  • Promise : 비동기 작업을 도와주는 도구
  • Observable: 연속적인 비동기 작업을 도와주는 도구

페이지네이션에서 마지막에 클릭한 페이지를 요청하면, 이전에 클릭해서 요청한 것은 취소되고 리렌더가 되면 안된다.

예를 들어, 3번페이지를 요청했다가 빠르게 5번 페이지를 요청했을 경우 3번 페이지 요청을 취소 후 5번 페이지를 보내줘야 하는데, 백엔드에서는 3번페이지를 보여주게 된다.

이런경우에는 3번 페이지 요청을 취소해야 한다. 그렇지 않으면 사용자의 불편한 경험을 초해 할 수 있기 때문이다.

Promise는 await해야 하므로 이런 방법이 불가능하다.

Observable은 연속적인 페이지 클릭 / 연속적인 검색어 변경 시 사용한다.
-> 반응형 프로그래밍

함수형 프로그래밍 / 반응형 프로그래밍

  • 함수형 프로그래밍 : 함수들을 체이닝해서 코드 작성 가능([].filter().map().forEach())
  • 반응형 프로그래밍 : 연속적인 기능들에 반응해서 사용하는 것
    -> reactive X (rx.js) / zen-observable : 반응형 프로그래밍 라이브러리

apollo에서는 observable 기반, zen-observable 사용

zen-observable 설치
yarn add zen-observable
yarn add --dev @types/zen-observable

  • fromPromise : 연속적인 쿼리를 실행시킬 때
  • flatMap : 연속적인 쿼리를 순차적으로 실행

fromPromise
onError 라는 함수는 return타입으로 Observable타입을 받는다.
그러나, 우리가 리턴해주는 값은 promise이기 때문에 Observable타입으로 바꿔줄 도구가 필요하다.
fromPromise 는 이때 사용하며, promise타입을 Observable타입으로 바꿔주는 도구이다.

profile
프론트엔드 개발자 도전기

0개의 댓글