-
Notifications
You must be signed in to change notification settings - Fork 8
로그인, 로그아웃 흐름 정리
ggyool edited this page Oct 5, 2021
·
4 revisions
AccessToken: 1시간, RefreshToken: 7일이라고 가정
a. 소셜로그인을 선택하는 창이 뜨고 소셜 로그인을 한다.
b. 성공시 redirect 방식으로 code 를 받는데 프론트에서는 그 code를 가지고 /login/{socialType} 으로 요청한다.
c. code는 일회용인데 서버에서는 이 code를 가지고 깃헙, 구글 같은 소셜에게 api 를 날려 유저 정보에 접근할 수 있는 AccessToken 을 받음
d. 서버에서는 받은 AccessToken 을 가지고 유저 정보를 받아오고 서비스에서 이용함 (아마 30분쯤 유효할듯)
(유저정보에는 소셜에서 관리하는 SocailId 가 있어, 보또보 DB 에 해당 소셜 사용자가 있는지 검사하면 보또보의 회원인지 알 수 있음)
e. 이미 서비스를 이용하던 사용자라면 보또보 DB 에서 정보를 빼오고, 뉴비라면 DB에 정보를 넣어준다.
f. 보또보 DB에는 유저를 관리하는 정수 UserId 값이 있는데 그 값을 이용하여 보또보의 AccessToken 과 RefreshToekn을 발급한다.
g. 요청에 대한 응답으로 프론트에게 토큰을 넘겨준다.
AccessToken 은 body로 넘겨주고
RefreshToken 은 쿠키에 넘겨준다. (ex. BTOKEN_REFRESH=jwt.refresh.token)
서버에서 쿠키를 추가할 때 HttpOnly, Secure 설정을 해준다.
HttpOnly: javascript의 document.cookie 로 접근 불가
Secure: HTTPS 가 아니면 쿠키를 전달하지 않음 (localhost는 예외)
Refresh 토큰은 따로 규격이 없는 것 같아서, 쿠키에 담기로 정했고 XSS 로 값을 빼가는 것을 막기 위해 HttpOnly 를 넣었고,
WireShark 같은 툴로 가로채는 것을 막기 위해 Secure 옵션을 넣었음.
암튼 정리하면 Refresh Token은 백엔드단에서 쿠키에 넣어주고 보안적인 설정도 해두었음
프론트에서 credentials=true 설정만 해주면 다음 요청의 쿠키에 포함됨
프론트에서 로그인 시 받은 AccessToken을 인증이 필요한 요청시 함께 보낸다. (Authorization 헤더에 AccessToken을 넣어서 요청)
백엔드에서는 올바른 토큰인지 검증 후 요청에 맞는 응답을 내려준다.
서버에서 아래 순서로 검증을 진행한다.
a. AccessToken 이 만료됨을 확인하고, 쿠키를 확인하여 RefreshToken 을 꺼내온다.
b. 꺼내온 RefreshToken이 올바른지 검증한다.
- 올바른 RefreshToken 이라면 토큰 재발급을 유도하는 예외를 던진다. (code: A008, message: 액세스 토큰 재발급이 필요합니다.)
-> 프론트에서 해당 예외를 핸들링하여 /token 으로 요청해야함
- 올바르지 않다면 로그인을 유도하는 예외를 던진다. (code: A001, message: 토큰이 유효하지 않습니다.)
-> 다시 로그인하게 만들어야함 (1번으로 돌아가도록)
AccessToken만 재발급 하면 되지만 우리는 RefreshToken 도 재발급한다.
로그인과 마찬가지로 AccessToken 은 body 에 RefreshToken 은 쿠키에 담아서 프론트로 넘겨준다.
RefreshToken을 재발급하는 장점은 서비스를 계속 이용한다고 가정하면 로그인이 풀리지 않는다.
토큰의 유효기간인 7일 안에 요청을 한 번이라도 하면 재발급 받기 때문에 7일 이라는 시간도 갱신되기 때문
또한 보안적으로도 재발급 하는 방향이 좋다고 생각함
새로운 토큰으로 3번의 /workbook/1 을 다시 한번 요청한다.
기존 AccessToken만 있을 때는 따로 로그아웃 api 가 필요 없었음. 프론트에서 안 보내면 되기 때문.
하지만 RefreshToken이 생기면서 필요해짐 서버에서는 RefreshToken을 Redis라는 인메모리 DB에 넣어서 관리하고 있음 (빠른 디비).
RefreshToken과 AccessToken 둘 다 jwt로 만드는데, 서버측에서 아무데도 저장하지 않는 AceessToken과는 달리
RefreshToken은 데이터베이스 (우리의 경우 Redis) 에 HashMap<UserId, RefreshToken> 형식으로 저장함.
우리는 RefreshToken이 만료되지 않았음에도 새로운 환경에서 로그인을 하면
재발급 하는 구조이기 때문에 JWT 기준에서는 유효한 토큰이 여러개 존재할 수 있음.
따라서 유저 한 명당 가장 최근에 발급한 하나의 RefreshToken만 redis에 저장함.
즉, 어떤 유저의 RefreshToken이 redis에 있는데 새로운 환경에서 로그인을 하면
그 때 새로 발급 받은 RefreshToken으로 redis 안에 있는 RefreshToken을 대체함.
1. RefreshToken이 유효한 경우
- redis에서 유저의 최신 RefreshToken 정보를 삭제한다
- 유저에게 새로운 쿠키를 set-cookie 해준다. 이 새로운 쿠키안의 RefreshToken은 값이 없고, 쿠키의 MaxAge 는 0 이다
- no-content로 응답한다
2. RefreshToken이 유효하지 않은 경우
- 유저에게 새로운 쿠키를 set-cookie 해준다. 이 새로운 쿠키안의 RefreshToken은 값이 없고, 쿠키의 MaxAge 는 0 이다
- no-content로 응답한다
Code Convention
- AWS 배포 및 Jenkins CI/CD 🐳
- Nginx로 로드 밸런싱하기
- How to Git Rebase?
- 잘못된 깃 브랜치에서 탈출하기
- 서브모듈 도입기
- 소나큐브 도입기
- Flyway 도입기
- DB Replication을 위한 데이터베이스 환경 설정
- 무중단 배포 도입기
- nginx 설정파일 변경하는 방법
- 로그인, 로그아웃 흐름정리
- About Redis
- Criteria -> QueryDSL로 변경
- S3 파일 업로드 구조
2차 ~ 4차 회의 및 데일리 미팅은 디스코드에서 진행되어 이슈로 반영되었습니다.
이후 회의 및 데일리 미팅은 디스코드에서 진행되어 이슈로 반영되었습니다.