Skip to content

로그인 유지

Wang Hoeun edited this page Apr 12, 2023 · 7 revisions

Co-nect 프로젝트 로그인 유지 방법 설명에 앞서 로그인 유지에 대해 간단한 설명을 해보겠다.

1. Authentication | Authorization

웹페이지 내부에서 특정 서비스를 활용할 때 Authentication(인증), Authorizationi(인가) 즉, 로그인권한을 요구하는 경우가 존재한다.

ID | Password를 통해 서비스의 권한이 주어진 사용자 인지 확인하는 로그인 과정에 인증이 필요하고

인증을 받은 이후에 특정 서비스 활용 행위에는 권한이 필요하다.

2. HTTP Protocol의 특징

그럼, ID | Password를 입력 한 후 데이터를 http를 통해 전달하면 되지 않을까? 이렇게 생각하면 로그인 정이 아주 간단하게 느껴지는데, http 프로토콜의 특징이자 약점을 살펴보면 추가적인 작업이 필요할 거라는 것을 알게 된다.

1. Connectionless. Protocol 비연결지향

클라이언트가 서버에 요청했을 때, 그 요청에 맞는 응답을 보낸 후 연결을 끊는 처리 방식.

2. Stateless Protocol (상태정보 유지 안 함)

클라이언트의 상태 정보를 가지지 않는 서버처리방식.

클라이언트와 첫번째 통신에서 데이터를 주고받았다 해도, 두번째 통신에서 이전 데이터를 유지하지 않는다.


위와 같이 데이터를 유지하지 않는다면, 페이지 이동시 마다 로그인을 해야하거나 장바구니에서 상품을 선택했는데 구매페이지에서 상품의 정보가 사라지는 경우가 발생할 것이다.

이러한 Stateful 특성 때문에, 우리는 다양한 방법을 사용한다.

3. 로그인 유지 방법

로그인 유지 방법엔 크게 3가지가 존재한다.

3-1) Cookie 기반 인증

http 의 일종으로 웹사이트 방문 시, 그 사이트가 사용하고 있는 서버에서 사용자의 클라이언트에 저장하는 기록 데이터 파일이다.

http에서 클라이언트의 상태 정보를 클라이언트에 저장해두었다가 필요 시 정보를 참조, 재사용한다.

쿠키 동작순서

  1. 클라이언트 요청
  2. 웹서버는 쿠키생성
  3. 생성한 쿠키에 정보를 담아 http화면을 돌려줄때 같이 클라이언트에게 넘긴다.
  4. 넘겨받은 쿠키는 클라이언트가 가지고 있다가 다시 서버에 요청 시, 쿠키를 함꼐 전송.
  5. 동일 사이트 재방문시 클라이언트 pc에 해당쿠키가 있는 경우, 요청페이지와 함께 쿠키 전송.

3-2) Session 기반 인증

사용자가 웹 서버에 접속해 있는 상태를 기억하는 방법이다. 사용자가 로그인하면 서버는 세션 저장소에 사용자의 정보를 조회하여 Session ID를 발급하고, 발급된 id는 브라우저의 쿠키(=세션 쿠키)에 저장한다.

이를 이용해 사용자가 요청을 보낼 때마다 서버는 세션을 조회하여 로그인 여부를 확인하여 로그인 상태를 유지할 수 있다. (서버에서 Session ID는 메모리, 디스크, 데이터베이스에 저장된다.)

브라우저를 닫거나, 서버에서 세션을 삭제했을 때 삭제되므로, 쿠키보다 보안이 좋다. 하지만 서버를 재부팅 해야할 때 세션 정보가 사라지게 되기 때문에 서버를 여러 대 사용한다면 신경써야하는 부분이 많아질 수 있다.

세션 동작순서 정리

  1. 클라이언트 요청
  2. 접근한 클라이언트의 request-header필드인 cookie 확인하여, 클라이언트가 해당 세션 ID 보냈는지 확인
  3. 세션 ID가 존재하지 않는다면, 서버는 세션ID를 생성해 클라이언트에게 전송.
  4. 서버에서 클라이언트로 준 세션ID를 쿠키를 사용해 서버에 저장한다.
  5. 클라이언트는 재 접속 시 쿠키를 이용하여 세션 ID값을 서버에 전달한다.

3-3) token 기반 인증

token은 로그인 이후 서버가 만들어 주는 문자열이다. 이 토큰 내부에는 사용자 로그인 정보, 서버에서 발급 되었음을 증명하는 서명이 들어있어 이를 이용해 로그인을 유지하곤 한다.

토큰에는 서버에서 발급 되었음을 증명하는 서명이 들어있기 때문에 *무결성(정보가 변경, 위조되지 않는 성질)*이 보장된다. 이를 이용해 사용자가 요청을 보낼 때마다 토큰과 함께 요청을 보내고, 서버에서는 요청에서 받은 토큰이 유효한지 검사하여 응답한다.

서버에서 사용자 로그인 정보를 기억하기 위해 사용하는 리소스가 적고, 서버가 여러 개 늘어나더라도 요청을 보내는 쪽(클라이언트)에서 토큰을 소유하고 있으므로 로그인 상태를 공유하고 있을 필요가 없다는 장점이 있다.

4. JWT(JSON Web Token)

JWT는 데이터가 JSON으로 이루어져 있는 토큰을 말하고, 로그인 유지 방법 중 토큰 기반 인증을 위해 사용된다.

JWT의 구조

JWT의 구조는 점(.)으로 구분된 세 부분으로 구성되며 다음과 같은 형태를 갖는다.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Co-nect에서의 JWT 활용

실제 Co-nect 프로젝트에서도 JWT를 활용하여 로그인 유지를 시행하였고, 그에 대한 로그인 과정은 다음과 같다.


💡 1. 사용자가 **ID와 Password**를 입력하면 클라이언트가 서버로 전달한다.
  1. 서버는 전달받은 ID와 Password를 검증하고 Access token과 Refresh token, Access token의 만료시간을 반환해준다. 이때 생성한 Refresh token은 DB에 {ID, Refresh token}으로 저장.

  2. 클라이언트는 반환 받은 Access token을 API 호출 마다 header에 붙여서 전송한다. 이때, local storage에 저장하여준다.

  3. 서버는 api 호출을 받을 시 header의 Access token을 확인하고 유효한지, 만료기간이 지났는지 체크 후 api를 동작시킨다.

  4. Acees token의 만료기간이 지나거나, 30초 미만으로 남았다면, 서버에게 refresh token 을 붙여 reIssue 요청을 보낸다.

  5. 서버는 reIssue 요청이 들어오면, Refresh token이 DB에 있는지 확인 후, Access token과 새로운 만료 시간을 반환한다.


위 로그인 과정에서 보면 3번 항목에서 local storage에 token을 저장한다는 부분이 있는데, 이에 대해 좀 더 자세히 설명해보겠다.

5. JWT 방식의 문제점

token 기반 인증 방식이 session 인증 방식보다 좋은 방법처럼 보이는데, 토큰 방식 인증에는 문제점이 있다.

만약 악의적인 사용자가 토큰을 탈취해버린다면 이를 무효화할 방법이 없다. JWT는 개인정보나 다름이 없는데, 이를 아무데나 저장하게 된다면, 보안 관련 대책이 없는 상태가 되어버릴 것이기 때문이다.

그렇다고 해서 JWT를 그저 private variable에만 저장한다면 화면을 새로고침할 때마다 사라지는 휘발성으로 인 해 매번 새로 로그인을 해야하는 번거로움이 생길 것이다.

그럼 어디에 저장할 수 있을까?

JWT 저장하기 위한 장소에는 대표적으로 localStoragecookie 2가지가 있다.

이때 cookie와 localStorage는 둘다 다른 목적을 가지고 있기 때문에 무엇이 옳다고 하기는 애매한 부분이 있다. 각각의 쓰임새에 따라 적합한 방법을 선택해야 한다.

1. Cookie

cookie는 서버측과 클라이언트 측에서 cookie 데이터를 사용하는 api가 존재한다.

저장된 cookie 데이터의 쓰임이 양쪽 모두이냐를 고려 해야 하며

만약 _서버쪽 사용이 필수적이고 잦다_면 로컬 저장소가 아닌 클라이언트 서버와의 인터렉션이 좀더 효과적인 cookie 값을 사용하는 것이 좋을 것이다.

그리고 우리가 어떤 웹사이트에 들어가면 항상 보는 광고 7일동안 보지 않기 역시 cookie 기능이기에 localStorage에서는 없는 기간 기능을 활용 할 수 있다.

2. localStorage (+sessionStorage)

localStorage는 로컬에 도메인 별로 지속되는 storage이다.

cookie와는 달리 localStorage는 js 객체 자체를 넣는 것 역시 가능하며 문자열에 크기 제한이 있는 cookie에 비해서 비교 우위를 가진다.

그리고 세션을 이용 시에 reauest와 response시에 모든 쿠키를 다 넘겨야 했는데 원래 비용이 큰 http 통신에 더 큰 하를 준다.

브라우저가 종료되면 자동으로 사라지는 쿠키를 재현하기 위해서 sessionStorage를 도입하였다. localStorage와 sessionStorage 둘다 저장 공간으로 사용할 수 있는데, 이 둘의 가장 큰 차이점이라면 저장소로서의 기능은 대부분 동일하며 단지 sessionStorage의 경우 session이 종료되면 저장된 데이터도 함께 사라진다는 점이 다른 점이다.


이처럼 cookie와 비교하였을 때 클라이언트상에서 데이터를 보관하는 것이 좋겠다는 결론을 내렸고, 취소 요청을 다시 보내지 않아도 되는 sessionStorage도 존재하지만 보편적으로 많이 사용하는 localStorage를 활용하여 token을 저장하였다.

💡 localStorage 설명과 사용법 https://inpa.tistory.com/entry/JS-📚-localStorage-sessionStorage#로컬_스토리지의_우위성


6. Co-nect에서의 로그인 유지

위와 같은 이유들로 현재 Co-nect에선 token을 localStorage에 저장하여 로그인 유지를 진행하고 있다.

publicApi / privateApi

token의 존재 여부로 구분 되는 public 한 api 요청과 private한 api요청에 따라 api요청 코드를 구분 지었고, 폴더 구조와 코드는 다음과 같다.

폴더 구조

image

api 폴더에 instance 폴더를 생성하여 privateApiInstance와 publicApiInstance를 생성하였다.

코드

publicApi코드 와는 다르게 privateApi는

const setAcessTokenInRequestConfig = (config) => {
  const accessToken = handleToken.getAccessToken();
  const refreshToken = handleToken.getRefreshToken();
  // 요청을 보내기 전에 수행할 로직

  if (!config?.headers || !accessToken || !refreshToken) {
    return config;
  }
  config.headers.Authorization = accessToken;
  config.headers[TOKEN.REFRESH] = refreshToken;
  return config;
};

다음과 같이 token에 존재 여부에 따른 request요청을 구현하였다.

댓글 Api 요청

로그인을 하지 않아도 댓글을 볼 수 있지만, 직접 댓글을 쓰는 작업은 불가능 하다.

따라서 그에 따른 api 요청을 publicApiInstance와 privateApiInstance로 구분하였다.

image

댓글을 확인하기 위한 get 요청은 public 요청, 댓글을 작성하기 위한 post 요청은 private인걸 확인할 수 있다.

다양한 트러블 슈팅

로그인 유지 방안을 모색 하면서 다양한 이슈들이 발생하였고, 그에 따른 기록은 Notion 회의록에 기록해두었다.

로그인 방식 정리

Day7-[BE]와 배포,api,로그인 등 회의

참고자료

https://velog.io/@apparatus1/로그인-인증-방식-웹-로그인-유지에-대해

https://cheershennah.tistory.com/135

https://inpa.tistory.com/entry/JS-📚-localStorage-sessionStorage#로컬_스토리지의_우위성

Clone this wiki locally