Skip to content

Commit bbe7ef7

Browse files
authored
feat: 에러 시 http 응답 코드 변경 (#118)
* feat: Redis 설정 * feat: 소셜로그인, 재발급 시 refresh token을 redis에 저장/삭제/조회 * feat: 로그아웃, 회원 탈퇴 시 Redis에서 Refresh Token 삭제 * refactor: jwtFilter 중복 코드 제거 * feat: 블랙리스트 토큰 여부 적용 * feat: 블랙리스트 토큰 저장 구현 * feat: 탈퇴 시 블랙리스트 토큰 저장 적용 * test: 탈퇴 시 블랙리스트 토큰 저장 적용 * fix: 누락된 문서 추가 * refactor: 로그아웃, 탈퇴 시 사용 API 통일 * 새로ì�ci: 개발계용 dockerfile 생성 * ci: 개발계 배포 스크립트 * test: Redis 미기동으로 테스트 실패 방지 * ci: 배포 스크립트 수정 * feat: RedisConfig 삭제 (Spring Boot 자동설정 사용) * test: redis mocking * chore: 에러코드 수정 * chore: 불필요 요소 삭제 * fix: JWT 로그아웃 필터 유형 변경 * test: JWT 로그아웃 필터 관련 테스트 코드 수정 * fix: 트랜잭션 전파 수정 * feat: 에러코드 추가 * chore: 불필요 요소 삭제 * chore: 주석 수정 * fix: 누락된 @transactional 추가 * feat: 에러 처리 추가 * feat: 토큰 오류 시 http 응답 코드 변경 * fix: 에러 타입에 따른 응답 변경 * test: 에러 타입에 따른 응답 변경
1 parent 140eef3 commit bbe7ef7

File tree

7 files changed

+25
-15
lines changed

7 files changed

+25
-15
lines changed

capturecat-core/src/main/java/com/capturecat/core/api/auth/TokenController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public ResponseEntity<?> reissue(
3434
newTokenMap = tokenIssueService.reissue(authHeader);
3535
} catch (CoreException e) {
3636
return ResponseEntity
37-
.badRequest()
37+
.status(e.getErrorType().getStatus())
3838
.body(ApiResponse.error(e.getErrorType()));
3939
}
4040

capturecat-core/src/main/java/com/capturecat/core/config/jwt/JwtFilter.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.fasterxml.jackson.databind.ObjectMapper;
1919

20+
import io.jsonwebtoken.ExpiredJwtException;
2021
import lombok.RequiredArgsConstructor;
2122
import lombok.extern.slf4j.Slf4j;
2223

@@ -47,11 +48,16 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
4748
String accessToken = jwtUtil.resolveToken(authHeader); // "Bearer " 이후 토큰
4849

4950
// 토큰 유효성 검사
50-
if (!jwtUtil.isAccessToken(accessToken)
51-
|| !jwtUtil.isValid(accessToken)
52-
|| tokenService.isBlacklisted(accessToken)) {
53-
//만료 시 client에 즉시 응답. client는 재발급 요청 수행.
54-
rejectInvalidToken(response, ErrorType.INVALID_ACCESS_TOKEN);
51+
try {
52+
if (!jwtUtil.isAccessToken(accessToken)
53+
|| !jwtUtil.isValid(accessToken)
54+
|| tokenService.isBlacklisted(accessToken)) {
55+
//만료 시 client에 즉시 응답. client는 재발급 요청 수행.
56+
rejectInvalidToken(response, ErrorType.INVALID_ACCESS_TOKEN);
57+
return;
58+
}
59+
} catch (ExpiredJwtException e) {
60+
rejectInvalidToken(response, ErrorType.ACCESS_TOKEN_EXPIRED);
5561
return;
5662
}
5763

capturecat-core/src/main/java/com/capturecat/core/config/jwt/JwtUtil.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,12 @@ private Claims extractClaims(String token) {
7070

7171
/**
7272
* 만료 여부 및 유효성 검증
73+
* ExpiredJwtException 이 발생할 경우 호출 부에서 ACCESS or REFRESH TOKEN EXPIRED로 받아야한다.
7374
*/
7475
public boolean isValid(String token) {
7576
try {
7677
extractClaims(token); // parseSignedClaims 호출 시 자동 만료 검증 (예외 던짐)
77-
} catch (ExpiredJwtException | SignatureException | MalformedJwtException | IllegalArgumentException e) {
78+
} catch (SignatureException | MalformedJwtException | IllegalArgumentException e) {
7879
return false;
7980
}
8081
return true;

capturecat-core/src/main/java/com/capturecat/core/service/auth/TokenService.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,9 @@ public String parseRefreshToken(String authHeader) {
8585
throw new CoreException(ErrorType.INVALID_REFRESH_TOKEN);
8686
}
8787
} catch (ExpiredJwtException e) {
88-
throw new CoreException(ErrorType.REFRESH_TOKEN_EXPIRED);
88+
throw new CoreException(ErrorType.REFRESH_TOKEN_EXPIRED, e.getMessage());
8989
} catch (SignatureException | MalformedJwtException | IllegalArgumentException e) {
90-
throw new CoreException(ErrorType.INVALID_REFRESH_TOKEN);
90+
throw new CoreException(ErrorType.INVALID_REFRESH_TOKEN, e.getMessage());
9191
}
9292

9393
return refreshToken;
@@ -112,7 +112,10 @@ public void revokeUserTokens(String accessTokenHeader, String refreshTokenHeader
112112
try {
113113
blacklistAccessToken(accessTokenHeader);
114114
deleteValidRefreshToken(refreshTokenHeader);
115+
} catch (CoreException e) {
116+
throw e;
115117
} catch (Exception e) {
118+
log.error("[revokeUserTokens] Unexpected error", e);
116119
throw new CoreException(ErrorType.INTERNAL_SERVER_ERROR);
117120
}
118121
}

capturecat-core/src/main/java/com/capturecat/core/support/error/ErrorCode.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ public enum ErrorCode {
2020
ALREADY_EXISTS_USERNAME("이미 등록된 회원 이름입니다."),
2121
UNKNOWN_ROLE("존재하지 않는 권한입니다."),
2222
NOT_FOUND_USER("사용자를 찾을 수 없습니다."),
23-
ACCESS_TOKEN_EXPIRED("Access token이 만료됐습니다."),
24-
REFRESH_TOKEN_EXPIRED("Refresh token이 만료됐습니다."),
23+
ACCESS_TOKEN_EXPIRED("Access token이 만료됐습니다. 재발급 해주세요."),
24+
REFRESH_TOKEN_EXPIRED("Refresh token이 만료됐습니다. 다시 로그인해주세요."),
2525
INVALID_ACCESS_TOKEN("Access token이 유효하지 않습니다."),
2626
INVALID_REFRESH_TOKEN("Refresh token이 유효하지 않습니다."),
2727
IMAGE_ACCESS_DENIED("요청하신 이미지에 접근할 권한이 없습니다. 본인 소유가 아니면 접근이 제한됩니다."),

capturecat-core/src/main/java/com/capturecat/core/support/error/ErrorType.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ public enum ErrorType {
2222
JOIN_FAIL(HttpStatus.BAD_REQUEST, ErrorCode.ALREADY_EXISTS_USERNAME, LogLevel.WARN),
2323
LOGIN_FAIL(HttpStatus.BAD_REQUEST, ErrorCode.INVALID_REQUEST, LogLevel.WARN),
2424
VALIDATION_FAIL(HttpStatus.BAD_REQUEST, ErrorCode.BEAN_VALIDATION_FAIL, LogLevel.WARN),
25-
INVALID_JWT(HttpStatus.BAD_REQUEST, ErrorCode.BEAN_VALIDATION_FAIL, LogLevel.WARN),
25+
INVALID_JWT(HttpStatus.UNAUTHORIZED, ErrorCode.BEAN_VALIDATION_FAIL, LogLevel.WARN),
2626
UNKNOWN_ROLE(HttpStatus.BAD_REQUEST, ErrorCode.UNKNOWN_ROLE, LogLevel.WARN),
2727
USER_NOT_FOUND(HttpStatus.NOT_FOUND, ErrorCode.NOT_FOUND_USER, LogLevel.WARN),
28-
ACCESS_TOKEN_EXPIRED(HttpStatus.BAD_REQUEST, ErrorCode.ACCESS_TOKEN_EXPIRED, LogLevel.WARN),
29-
REFRESH_TOKEN_EXPIRED(HttpStatus.BAD_REQUEST, ErrorCode.REFRESH_TOKEN_EXPIRED, LogLevel.WARN),
28+
ACCESS_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, ErrorCode.ACCESS_TOKEN_EXPIRED, LogLevel.WARN),
29+
REFRESH_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, ErrorCode.REFRESH_TOKEN_EXPIRED, LogLevel.WARN),
3030
INVALID_ACCESS_TOKEN(HttpStatus.UNAUTHORIZED, ErrorCode.INVALID_ACCESS_TOKEN, LogLevel.WARN),
3131
INVALID_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, ErrorCode.INVALID_REFRESH_TOKEN, LogLevel.WARN),
3232
IMAGE_ACCESS_DENIED(HttpStatus.FORBIDDEN, ErrorCode.IMAGE_ACCESS_DENIED, LogLevel.WARN),

capturecat-core/src/test/java/com/capturecat/core/api/auth/TokenApiTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ void reissue_withValidRefreshToken_returnsNewTokensInHeaders() throws Exception
9292
void reissue_withInvalidRefreshToken_returnsBadRequest() throws Exception {
9393
mockMvc.perform(post("/token/reissue")
9494
.header(JwtUtil.REFRESH_TOKEN_HEADER, "Bearer invalid.token"))
95-
.andExpect(status().isBadRequest())
95+
.andExpect(status().isUnauthorized())
9696
.andExpect(jsonPath("$.result").value("ERROR"))
9797
.andExpect(jsonPath("$.error").exists());
9898
}

0 commit comments

Comments
 (0)