JWT(Json Web Token) 인증방식의 개념과 장점을 크게 해치지 않고 요구사항을 만족할 수 있는 방안을 찾아보자.
1. 서버 기반 vs 토큰 기반
SESSION
- 서버에서 사용자의 인증 정보를 관리하는 것을 의미합니다.
- 요청을 받으면 클라이언트의 상태를 서버에서 지속적으로 유지하고 관리합니다. Stateful
- 사용자의 증가함에 따라 성능 저하를 야기하기도 하며, 확장성이 떨어집니다.
TOKEN
- 사용자의 인증 정보를 서버가 아닌 클라이언트에서 관리합니다.
- 서버는 클라이언트의 상태를 관리할 필요가 없고, 헤더로 넘어온 토큰을 해석하여 인증 받은 사용자인지 확인합니다.
- 서버는 토큰 내의 정보와 키 값에 문제가 없다면 올바른 토큰으로 취급합니다.
- 탈취에 대한 토큰 내 정보에 만료 시간을 담아 사용 기간을 제한하여 보안 처리를 합니다.
Cookie / Session / Token 인증 방식 종류
2. JWT의 방향성과 로그아웃
로그아웃을 진행하기 위해선 로그인, 로그아웃을 한 클라이언트가 관리되어야 합니다. JWT는 Stateless하고 서버의 부하를 줄인 것에 대한 Side-Effect로 생각할 수도 있겠네요. JWT의 방향성은 로그아웃보다는 로그인을 더욱 간결하게 하기 위함이고 로그아웃 시 브라우저에서 저장된 토큰을 없애는 정도만 진행하지 확실한 로그아웃을 진행할 수 없습니다.
3. 구현 방안
요구사항
- 비밀번호 변경 시 로그인된 모든 디바이스에서 로그아웃 됩니다.
달성 목표
- JWT의 Statelss를 최대한 해치지 않도록 하자. (이럴바엔 세션을 쓰지라는 생각이 들지 않도록…)
- 비밀번호 변경 전에 로그인한 유저들을 구분한다.
시나리오
- 비밀번호 변경 시점에 Email(Unique함)과 함께 변경 시간을 Redis에 저장합니다.
- 클라이언트가 발급한 토큰에 발급 시간(issuedAt)을 함께 담아줍니다.
- 요청에 대해 토큰 검증을 진행한다. (토큰 만료 시간 검증)
- 추가적으로 토큰 발급 시간이 비밀번호 변경 시점 이전인지 확인합니다.
a. Redis에 저장된 변경 시간이 없다면 PASS
b. 변경 시간 이후에 발급된 토큰이라면 PASS
c.변경 시간 이전에 발급된 토큰이라면 NON-PASS
- Access Token 만료 시간이 2시간으로 설정했으니 Redis의 캐시도 2시간 TTL로 설정합니다.
의견
로그인 시 토큰을 모두 저장하고 세션 종료를 시키는 방안도 있겠지만(with.블랙리스트) 서버에 인증을 위한 데이터가 남지 않도록 최소화 하는 것이 서버 기반이 인증이 아닌 토큰 기반 인증을 사용한 이유를 잘 살릴 수 있다는 의견입니다.
++Why?
Q1. 왜 MSA가 많이 보급 되면서 Client-side Session인 JWT(JSON Web Token) 방식이 많이 활용되는가?
A. 하나의 서비스를 구성하기 위해 기존보다 훨씬 더 많은 서버들이 발생하는데 모두 사용자 인증이 필요할 것이다. 서버가 늘어난 만큼 세션 인증 서버에 몇 배로 부하가 가는 환경이 될 것입니다. 이점이 JWT와 잘 어울리는 것이 아닐까