Skip to content

[BE] 로그인 로그아웃 처리

Jeongmin edited this page Dec 14, 2023 · 3 revisions

로그인 상태 유지 방식

우리 팀은 로그인 상태 유지를 위해 토큰 방식을 사용하기로 결정하였다. 로그인 시 access tokenrefresh token을 발급하고, access token이 만료될 때 마다 refresh token을 전송하여 access token을 새로 발급받는다. refresh token도 만료되면 로그인을 다시 진행해야 한다.

로그인 로직

우리 팀은 iOS 어플리케이션을 개발 중이기 때문에 Apple Login을 필수적으로 포함해야 했다. App Store에 OAuth 기능이 있는 어플리케이션을 출시하려면 반드시 Apple Login을 지원해야 하기 때문이다. 그래서 우선은 Apple Login만 구현을 해두고, 추후 여유가 생기면 다른 OAuth를 포함하기로 결정했다.

일반적으로 OAuth 기능을 사용한다고 하면 resource 서버의 자원을 가져다 쓰기 때문에 resource 서버에서 발급한 access tokenrefresh token이 필요하다. 그러나 우리 서비스에서는 애플 측의 자원을 이용해야 할 일이 없었기 때문에 애플 서버로부터 access tokenrefresh token을 발급받는 과정을 생략하고 구현하였다. 그 결과, 아래와 같이 로그인 로직을 구현했다.

  1. 클라이언트 측이 애플 서버에 로그인 요청을 보낸다.
  2. 요청 결과로 이메일 주소와 identity token을 받는다.
  3. 클라이언트 측은 이메일 주소와 identity token을 traveline 서버로 전달한다.
  4. traveline 서버는 identity token을 복호화 하여 사용자 고유 값을 얻어낸다.
  5. 사용자 고유 값을 이용해 신규 회원 여부를 판단한다. 신규 회원일 경우 회원 가입 처리를 진행한다.
  6. traveline 자체 발급 access tokenrefresh token을 담아 클라이언트 측에 응답을 보낸다.

애플 로그인의 복잡한 과정은 최대한 생략하여 간략하게 설명해보았다. 정확하고 자세한 로직이 궁금하다면 이 문서를 참고해보는 것을 추천한다.

로그아웃 로직 정리

기획 단계에서 필요한 API를 정리하면서, 막연하게 로그아웃 API도 필요할 것이라고 생각하고 개발을 시작했었다. 그런데 막상 개발을 해야 하는 시점이 되니 고민거리가 많아졌다. 서버 측에서는 사용자가 확실히 로그아웃 처리 되었다는 것을 확인할 길이 없었기 때문이다.

만약 굳이 굳이 사용자가 로그아웃 요청을 보내기 전 유효기간이 남은 refresh tokenaccess token을 어딘가에 따로 저장해둔다면? 사용자가 로그아웃을 하겠다며 refresh tokenaccess token을 서버쪽에 보내고 서버가 그 토큰들을 만료시킨대도 추후 사용자가 따로 저장해두었던 유효기간이 남은 토큰들을 다시 사용하면 그만이었다.

이 문제 때문에 검색을 해 본 결과 블랙리스트 DB를 따로 두고 구현하는 방법이 있다는 것을 알게 되었다. 블랙리스트 DB를 따로 두게 되면 로그아웃 요청이 들어왔을 때 유효기간이 남은 refresh token을 블랙리스트 DB에 저장한다. 추후 refresh 요청이 들어오면 access token을 발급해주기 전에 요청과 함께 온 refresh token이 블랙리스트에 존재하는지 확인하고 존재하지 않을 경우에만 access token을 재발급해준다.

블랙리스트 DB를 사용하면 확실한 로그아웃을 보장할 수 있지만, 블랙리스트 DB에서 주기적으로 만료된 토큰들을 삭제해주어야 하고, 블랙리스트를 관리하기 위한 NoSQL을 새로 연결해야 하는 등 추가적으로 필요한 작업이 많다고 느껴졌다. 그래서 복잡한 버전의 로그아웃, 간단한 버전의 로그아웃 로직을 작성한 뒤 멘토님께 조언을 구했다.

복잡 ver.

  1. 로그인 상태 확인 (가드)
  2. refresh token 블랙리스트 DB에 사용자의 refresh token 저장
  3. 성공 응답 전송
  4. 추후 refresh 요청이 들어오면 블랙리스트 DB에 해당 refresh token이 존재하는지 확인
  5. 사용자의 refresh token이 원래 유효기간을 다 채우면 블랙리스트 DB에서 삭제

❓ 세션 방식과 다른 점이 뭐지?

간단 ver.

  1. 로그인 상태 확인 (가드)
  2. 사용자로부터 받은 refresh 만료
  3. 성공 응답 전송
  4. 클라이언트 측은 성공 응답을 받으면 refresh를 스스로 삭제

❓ 클라이언트를 어떻게 믿지?

멘토님의 조언을 토대로 우리는 제 3의, 초간단 버전의 로그아웃 로직을 사용하기로 결정을 내렸다. 블랙리스트 DB를 두는 방식은 중복로그인을 방지해야 하거나 보안이 중요한 금융 서비스에서 주로 사용하고 일반적으로는 사용자가 로그아웃 요청을 할 경우 따로 서버 측에 요청을 보내지 않고, 클라이언트 측에서 access tokenrefresh token을 삭제하는 것으로 작업을 마무리 한다고 하셨다. 그래서 우리는 과감히 로그아웃 로직을 삭제하게 되었다!

가드의 역할

인가가 필요한 작업에서 손쉽게 access token을 확인하기 위해서 가드를 사용하기로 결정했다. 또한, 가드는 access token 확인 역할 뿐 아니라 신원 파악 역할도 진행한다. access tokenpayload에 회원 고유 id를 넣어두었기 때문이다. 또한, 복호화를 통해 알아낸 id를 request에 저장해두어 사용자 id 값이 필요한 서비스에서 사용할 수 있도록 하였다.

  1. 헤더에 토큰이 존재하는지 확인한다. 토큰이 존재하지 않을 경우 HttpExceptionthrow 한다.
  2. 디코딩을 수행한다.
  3. 유효기간 만료 시 HttpExceptionthrow 한다. (이건 jwt 모듈이 알아서 해준다. 직접 확인할 필요 X)
  4. payload 내의 id로 DB에서 사용자를 검색한다. 사용자가 존재하지 않을 경우 HttpExceptionthrow 한다.
  5. 위 과정을 모두 통과하면 payloadrequest['user']에 저장한다.
Clone this wiki locally