Skip to content

Commit

Permalink
refactor: #27 재발급된 accessToken과 refreshToken 로그아웃 처리
Browse files Browse the repository at this point in the history
  • Loading branch information
psychology50 committed Oct 11, 2023
1 parent daca4fd commit cff7b3a
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 25 deletions.
20 changes: 10 additions & 10 deletions src/main/java/com/kcy/fitapet/domain/member/api/MemberApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,19 @@ public ResponseEntity<?> signOut(
@AccessTokenInfo AccessToken accessToken,
@CookieValue(value = "refreshToken", required = false) @Valid String refreshToken,
HttpServletRequest request, HttpServletResponse response) {
if (accessToken.isReissued()) {
refreshToken = response.getHeader(HttpHeaders.SET_COOKIE).substring(AuthConstants.REFRESH_TOKEN.getValue().length() + 1);
log.info("reissued refresh token: {}", refreshToken);
}

memberAuthService.logout(accessToken, refreshToken);

ResponseCookie cookie;
if (refreshToken != null)
cookie = cookieUtil.deleteCookie(request, response, REFRESH_TOKEN.getValue())
.orElseThrow(() -> new AuthErrorException(AuthErrorCode.REFRESH_TOKEN_NOT_FOUND, "존재하지 않는 쿠키입니다."));
else
cookie = cookieUtil.createCookie(REFRESH_TOKEN.getValue(), "", 0);
if (!StringUtils.hasText(refreshToken)) {
return ResponseEntity.ok(SuccessResponse.noContent());
}

ResponseCookie cookie = cookieUtil.deleteCookie(request, response, REFRESH_TOKEN.getValue())
.orElseThrow(() -> new AuthErrorException(AuthErrorCode.REFRESH_TOKEN_NOT_FOUND, "존재하지 않는 쿠키입니다."));
return ResponseEntity.ok().header(HttpHeaders.SET_COOKIE, cookie.toString()).body(SuccessResponse.noContent());
}

Expand All @@ -151,11 +155,7 @@ public ResponseEntity<?> signOut(
})
@GetMapping("/refresh")
public ResponseEntity<?> refresh(@CookieValue("refreshToken") @Valid String refreshToken) {
if (refreshToken == null) {
throw new AuthErrorException(AuthErrorCode.REFRESH_TOKEN_NOT_FOUND, "존재하지 않는 쿠키입니다.");
}
Map<String, String> tokens = memberAuthService.refresh(refreshToken);

return getResponseEntity(tokens);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,11 @@ public Map<String, String> login(SignInReq dto) {
}

@Transactional
public void logout(AccessToken accessToken, String requestRefreshToken) {
if (requestRefreshToken != null)
public void logout(AccessToken requestAccessToken, String requestRefreshToken) {
forbiddenTokenService.register(requestAccessToken);

if (!StringUtils.hasText(requestRefreshToken))
refreshTokenService.logout(requestRefreshToken);
forbiddenTokenService.register(accessToken);
}

@Transactional
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
public record AccessToken(
String accessToken,
Long userId,
LocalDateTime expiryDate
LocalDateTime expiryDate,
boolean isReissued
) {
public static AccessToken of(String accessToken, Long userId, LocalDateTime expiryDate, boolean isReissued) {
return new AccessToken(accessToken, userId, expiryDate, isReissued);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package com.kcy.fitapet.global.common.resolver.access;

import com.kcy.fitapet.global.common.util.cookie.CookieUtil;
import com.kcy.fitapet.global.common.util.jwt.AuthConstants;
import com.kcy.fitapet.global.common.util.jwt.JwtUtil;
import com.kcy.fitapet.global.common.util.jwt.exception.AuthErrorCode;
import com.kcy.fitapet.global.common.util.jwt.exception.AuthErrorException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -23,6 +26,7 @@
@Component
public class AccessTokenInfoResolver implements HandlerMethodArgumentResolver {
private final JwtUtil jwtUtil;
private final CookieUtil cookieUtil;

@Override
public boolean supportsParameter(MethodParameter parameter) {
Expand All @@ -37,17 +41,28 @@ public Object resolveArgument(
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
final var httpServletRequest = (HttpServletRequest) webRequest.getNativeRequest();
String accessToken = jwtUtil.resolveToken(httpServletRequest.getHeader(AuthConstants.AUTH_HEADER.getValue()));
final var httpServletResponse = (HttpServletResponse) webRequest.getNativeResponse();
boolean isReissued = false;

if (!StringUtils.hasText(accessToken)) {
log.error("Access Token is empty");
throw new AuthErrorException(AuthErrorCode.EMPTY_ACCESS_TOKEN, "access token is empty");
String reissuedAccessToken = httpServletResponse.getHeader(AuthConstants.REISSUED_ACCESS_TOKEN.getValue());

String accessToken;
if (!StringUtils.hasText(reissuedAccessToken)) {
accessToken = jwtUtil.resolveToken(httpServletRequest.getHeader(AuthConstants.AUTH_HEADER.getValue()));

if (!StringUtils.hasText(accessToken)) {
log.error("Access Token is empty");
throw new AuthErrorException(AuthErrorCode.EMPTY_ACCESS_TOKEN, "access token is empty");
}
} else {
accessToken = reissuedAccessToken;
isReissued = true;
}

Long userId = jwtUtil.getUserIdFromToken(accessToken);
LocalDateTime expiryDate = jwtUtil.getExpiryDate(accessToken);
log.info("access token expiryDate : {}", expiryDate);

return new AccessToken(accessToken, userId, expiryDate);
return AccessToken.of(accessToken, userId, expiryDate, isReissued);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ protected ResponseEntity<ErrorResponse> handleAuthErrorException(AuthErrorExcept
return ResponseEntity.status(e.getErrorCode().getHttpStatus()).body(response);
}

/**
* API 호출 시 인가 관련 예외를 처리하는 메서드
* @param e AccessDeniedException
* @return ResponseEntity<ErrorResponse>
*/
@ExceptionHandler(AccessDeniedException.class)
protected ResponseEntity<ErrorResponse> handleAccessDeniedException(AccessDeniedException e) {
log.warn("handleAccessDeniedException : {}", e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ public class PreAuthorizeService {
public boolean test(Long requestMemberId) {
log.info("is start pre authorization check");

// authentication = SecurityContextHolder.getContext().getAuthentication();
log.info("user role type : {}",requestMemberId);
log.info("user role type : {}", requestMemberId);
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private String resolveAccessToken(HttpServletRequest request, HttpServletRespons
}

private String reissueAccessToken(HttpServletRequest request, HttpServletResponse response) {
Cookie refreshTokenCookie = cookieUtil.getCookie(request, REFRESH_TOKEN.getValue())
Cookie refreshTokenCookie = cookieUtil.getCookieFromRequest(request, REFRESH_TOKEN.getValue())
.orElseThrow(() -> new AuthErrorException(AuthErrorCode.REFRESH_TOKEN_NOT_FOUND, "Refresh token not found"));
String requestRefreshToken = refreshTokenCookie.getValue();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.stereotype.Component;

Expand All @@ -17,7 +18,7 @@ public class CookieUtil {
* @param cookieName String : 찾을 쿠키의 이름
* @return Optional<Cookie> : 쿠키가 존재하면 해당 쿠키를, 존재하지 않으면 Optional.empty()를 반환합니다.
*/
public Optional<Cookie> getCookie(HttpServletRequest request, String cookieName) {
public Optional<Cookie> getCookieFromRequest(HttpServletRequest request, String cookieName) {
Cookie[] cookies = request.getCookies();
if (cookies == null) {
return Optional.empty();
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jwt:
secret: ${JWT_SECRET}
token:
# milliseconds 단위
access-expiration-time: 1800000 # 30m (30 * 60 * 1000)
access-expiration-time: 2000 # 30m (30 * 60 * 1000)
refresh-expiration-time: 604800000 # 7d (7 * 24 * 60 * 60 * 1000)
sms-auth-expiration-time: 180000 # 3m (3 * 60 * 1000)

Expand Down

0 comments on commit cff7b3a

Please sign in to comment.