Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] feat: Refresh Token, Logout API 구현 #923

Merged
merged 6 commits into from
Nov 8, 2023

Conversation

gitchannn
Copy link
Collaborator

@gitchannn gitchannn commented Nov 8, 2023

closes #922

말랑아 하다보니깐 로그아웃 API도 같이 만들면 될 것 같아서 일단 만들어봤어! 프론트에는 알려줬는데 수정할 것 있으면 알려줘

구현 방법

로그아웃

  • Refresh 토큰을 별도로 받음.
  • Refresh 토큰이 유효한지, 현재 로그아웃된 사용자가 아닌지, 로그인된 사용자의 토큰이 맞는지 검증
  • Refresh 토큰을 BLACK_LIST 테이블에 저장

Refresh Token 발급

  • Refresh 토큰을 별도로 받음.
  • Refresh 토큰이 유효한지, 현재 로그아웃된 사용자의 토큰이 아닌지 검증
  • AccessToken, RefreshToken 현재 시간 기점으로 새롭게 발급

Refresh Token API

Request

GET /api/admin/auth/reissue-token
Refresh: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwiZXhwIjoxNzAwMDE1MTUzfQ.fGIV5IyT9aHptd-1c_fOhPVudpDkR-JOIKqZyAZ9Na_ZPwnOs-61OjBPehWhbVv5MMRa9qcseIZdo8I6GJ5PHA

Response

  • refreshToken 가 정상(조작되지 않음)이고, 만료되지 않은 경우

Header

200 OK HTTP/1.1

Body

{
    "accessToken": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwiZXhwIjoxNjk5NDkyMzMyfQ.kAsL4WF8lcIX8vQszUsVVn55qGsLvbUogFqksIDDUnteNravGt_i8OD3X0vq4ELXK9i_SiWen08L7fouAcrnPg",
    "refreshToken": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwiZXhwIjoxNzAwMDEwNzMyfQ.36Yjn3oUw4wq9qE-S0XZEzgOGSJt9VaRdVCoO7OJhBIsF9jUWd-r-4uMwYOY98mu7lZ1Ltc6KjrrkPYznH4Rlg",
    "grantType": "Bearer",
    "expiresIn": 86400
}
  • refreshToken 가 만료되었거나, 조작된 경우

Header

401 BAD REQUEST HTTP/1.1

Body

None

그리고, 추가적으로 Refresh Token을 사용하면서 서버 쪽에서도 refreshToken을 데이터베이스를 통해 관리하게 되었습니다. 따라서 로그아웃 로직을 구현할 때 기존에 프론트엔드에서 로컬 저장소에서 토큰을 모두 삭제하는 불완전한 방식으로 구현했던 것을 보완할 수 있게 되었습니다.

로그아웃 시에 해당 API를 사용하면 서버 측에서도 해당 refreshToken이 로그아웃된 사용자의 것이라는 사실을 인지해, 로그아웃 이후에도 refreshToken 을 누군가 사용하는 것을 막을 수 있습니다.

Logout API

Request

GET /api/admin/logout
Authorization: Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwiZXhwIjoxNjk5NDk2NzUzfQ.p-gAUwu6QgnD-8xSHeKDYPuT9ak413UOpiRmhkUluqYoDbbEBJsq1XQg1ahqHKzmufvc4MaTpoJI2g8yb7CkHQ
Refresh: eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIxIiwiZXhwIjoxNzAwMDE1MTUzfQ.fGIV5IyT9aHptd-1c_fOhPVudpDkR-JOIKqZyAZ9Na_ZPwnOs-61OjBPehWhbVv5MMRa9qcseIZdo8I6GJ5PHA

Response

204 NO CONTENT HTTP/1.1

Copy link

github-actions bot commented Nov 8, 2023

Unit Test Results

250 tests   250 ✔️  18s ⏱️
101 suites      0 💤
101 files        0

Results for commit bdbecbf.

♻️ This comment has been updated with latest results.

@gitchannn gitchannn self-assigned this Nov 8, 2023
@gitchannn gitchannn added 기능구현 ✅ 새로운 기능 추가에 대한 이슈 back-end 👩‍👩‍👦‍👦 백엔드 관련 이슈 labels Nov 8, 2023
Copy link
Member

@shin-mallang shin-mallang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생했어 깃짱!
코드 중복만 좀 해결하면 좋을 것 같은데, 바쁘면 일단 진행하자!
커멘트 확인 부탁해

Comment on lines 29 to 34
if (!blackListRepository.isValidRefreshToken(refreshToken)) {
throw new UnAuthorizationException("[ERROR] 이미 로그아웃된 사용자입니다!");
}

blackListRepository.save(new BlackList(refreshToken));
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 로그아웃된 사용자에 대해서 굳이 예외를 던질 필요는 없어보여!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그럼 그냥 넘어갈까?!

Comment on lines 23 to 25
if (!blackListRepository.isValidRefreshToken(refreshToken)) {
throw new UnAuthorizationException("[ERROR] 이미 로그아웃한 사용자입니다. 다시 로그인해 주세요");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거랑 유효성 검증 로직이 중복인 것 같은데, 원인이 서비스 단에서 비즈니스 로직을 담고 있기 때문인 것 같아.
도메인 레이어에 적절한 객체를 생성해서 그곳에서 진행해보면 어덜까?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅇㅋ 반영완료

Comment on lines 29 to 31
if (!blackListRepository.isValidRefreshToken(refreshToken)) {
throw new UnAuthorizationException("[ERROR] 이미 로그아웃된 사용자입니다!");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로그아웃이거나 블랙리스트이거나지 않아?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로그아웃하면 블랙리스트에 등록되는거 아냐?!?!
아니면 탈취당했다고 해서 블랙리스트에 넣은 경우를 고려한건가?

Comment on lines 9 to 10
@Query("SELECT CASE WHEN COUNT(bl) > 0 THEN false ELSE true END FROM BlackList bl WHERE bl.invalidRefreshToken = :refreshToken")
boolean isValidRefreshToken(String refreshToken);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isValid라는 비즈니스 로직이 Repository에 명시적으로 들어나는데, 이는 Repository의 책임 범위 밖인 것 같아.
existsByRefreshToken(); 이라는 네이밍은 어때?
그리고 쿼리가 좀 복잡한데, 다음과 같이 간단하게 쓸 수 있어.

default boolean existsByRefreshToken(String refreshToken) {
     return findByRefreshToken(refreshToken).isPresent();
}

Optional<BlackList> findByRefreshToken(String refreshToken);

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿뜨

@gitchannn gitchannn merged commit 3bb9544 into develop Nov 8, 2023
3 checks passed
@gitchannn gitchannn deleted the feature/922-refresh-token branch November 8, 2023 04:41
Copy link
Member

@shin-mallang shin-mallang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GOOD
@column 은 한번 통일성 맞춰야 할 것 같아~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
back-end 👩‍👩‍👦‍👦 백엔드 관련 이슈 기능구현 ✅ 새로운 기능 추가에 대한 이슈
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[BE] feat: refresh token 로직 구현
2 participants