Skip to content

Commit

Permalink
[FEAT #9]: ATK 재발급 로직 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
JungYoonShin committed Jun 2, 2024
1 parent 83372a5 commit 46e4dff
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public enum ErrorMessage {
MEMBER_NOT_FOUND(HttpStatus.NO_CONTENT.value(), "ID에 해당하는 사용자가 존재하지 않습니다."),
BLOG_NOT_FOUND(HttpStatus.NO_CONTENT.value(), "ID에 해당하는 블로그가 존재하지 않습니다."),
JWT_UNAUTHORIZED_EXCEPTION(HttpStatus.UNAUTHORIZED.value(), "사용자의 로그인 검증을 실패했습니다."),
EXPIRED_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED.value(), "리프레시 토큰이 만료되었습니다. 재로그인해주세요."),
EXPIRED_ACCESS_TOKEN(HttpStatus.UNAUTHORIZED.value(), "엑세스 토큰이 만료되었습니다. 재발급 받아주세요."),
MISMATCH_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED.value(), "실제 리프레시 토큰과 일치하지 않습니다. 재로그인해주세요.")
;

private final int status;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.sopt.seminar.controller;

import com.sopt.seminar.jwt.TokenInfo;
import com.sopt.seminar.service.dto.UserJoinResponse;
import com.sopt.seminar.global.ApiResponse;
import com.sopt.seminar.global.ApiUtils;
Expand All @@ -13,12 +14,12 @@

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/members") //v1은 버전관리할 때 이렇게 쓰곤 함
@RequestMapping("/api/v1") //v1은 버전관리할 때 이렇게 쓰곤 함
public class MemberController {

private final MemberService memberService;

@PostMapping
@PostMapping("/members")
public ResponseEntity<UserJoinResponse> postMember(
@RequestBody @Valid MemberCreateRequest memberCreate
) {
Expand All @@ -29,6 +30,11 @@ public ResponseEntity<UserJoinResponse> postMember(
);
}

@GetMapping("/members/reissue")
public ResponseEntity<TokenInfo> reissue(@RequestHeader String refreshToken) {
return ResponseEntity.ok(memberService.reissue(refreshToken));
}

@GetMapping("/{memberId}")
public ResponseEntity<ApiResponse<?>> findMemberById(@PathVariable("memberId") Long memberId) {
return ApiUtils.success(HttpStatus.OK, memberService.findMemberById(memberId));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.sopt.seminar.jwt;

import com.sopt.seminar.common.dto.ErrorMessage;
import com.sopt.seminar.exception.UnauthorizedException;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -73,6 +75,13 @@ private Claims getBody(final String token) {
.getBody();
}

public void matchRefreshToken(String refreshToken, String storedRefreshToken) {
if (!refreshToken.equals(storedRefreshToken)) {
throw new UnauthorizedException(ErrorMessage.MISMATCH_REFRESH_TOKEN);
}
}


public String getUserFromJwt(String token) {
Claims claims = getBody(token);
return claims.get(EMAIL).toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class SecurityConfig {
private final CustomAccessDeniedHandler customAccessDeniedHandler;


private static final String[] AUTH_WHITE_LIST = {"/api/v1/members", "/"};
private static final String[] AUTH_WHITE_LIST = {"/api/v1/members", "/", "/api/v1/members/reissue"};

@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.sopt.seminar.service;

import com.sopt.seminar.common.dto.ErrorMessage;
import com.sopt.seminar.exception.UnauthorizedException;
import com.sopt.seminar.jwt.JwtTokenProvider;
import com.sopt.seminar.jwt.TokenInfo;
import com.sopt.seminar.jwt.UserAuthentication;
Expand Down Expand Up @@ -43,10 +44,22 @@ public UserJoinResponse createMember(
UserAuthentication userAuthentication = UserAuthentication.createUserAuthentication(memberCreate.email());
TokenInfo token = issueTokenAndStoreRefreshToken(userAuthentication, member.getId());

return UserJoinResponse.of(
token.accessToken(),
token.refreshToken()
);
return UserJoinResponse.of(token.accessToken(), token.refreshToken());
}

public TokenInfo reissue(String refreshToken) {
jwtTokenProvider.validateToken(refreshToken);
String userEmail = jwtTokenProvider.getUserFromJwt(refreshToken);
System.out.println("userEmail = " + userEmail);
Member member = findMember(userEmail);

//리프레시 토큰 탈취여부 확인(탈취범이 정상 유저보다 먼저 재발급 받았을 경우 -> 재로그인 유도)
jwtTokenProvider.matchRefreshToken(refreshToken, findRefreshToken(member.getId()).getRefreshToken());

UserAuthentication userAuthentication = UserAuthentication.createUserAuthentication(userEmail);
TokenInfo token = issueTokenAndStoreRefreshToken(userAuthentication, member.getId());

return token;
}

public MemberDetailResponse findMemberById(Long memberId) {
Expand Down Expand Up @@ -81,6 +94,11 @@ public Member findMember(String email) {
.orElseThrow(()-> new NotFoundException(ErrorMessage.MEMBER_NOT_FOUND));
}

private RefreshToken findRefreshToken(Long userId) {
return refreshTokenRepository.findById(userId)
.orElseThrow(() -> new NotFoundException(ErrorMessage.EXPIRED_REFRESH_TOKEN));
}

private TokenInfo issueTokenAndStoreRefreshToken(Authentication authentication, Long userId) {
TokenInfo issuedToken = jwtTokenProvider.issueToken(authentication);
RefreshToken refreshToken = RefreshToken.builder()
Expand Down

0 comments on commit 46e4dff

Please sign in to comment.