From 0ba86d1e1c7cc0002124bad6d83910483e87d866 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=86=90=ED=99=8D=EC=84=9D?= <78216059+bayy1216@users.noreply.github.com> Date: Thu, 30 May 2024 17:38:20 +0900 Subject: [PATCH] =?UTF-8?q?[Feat]:=20=EC=97=90=EB=9F=AC=EC=9D=91=EB=8B=B5?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../global/api/ApiControllerAdvice.java | 80 +++++++++++++++++++ .../exception/UnauthorizedException.java | 7 ++ .../haedal/zzansuni/global/jwt/JwtUtils.java | 4 +- .../zzansuni/global/security/JwtProvider.java | 4 +- .../global/security/WebSecurityConfig.java | 13 +-- .../infrastructure/user/UserReaderImpl.java | 3 +- 6 files changed, 100 insertions(+), 11 deletions(-) create mode 100644 zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java create mode 100644 zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/exception/UnauthorizedException.java diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java new file mode 100644 index 0000000..2f8d5cc --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/api/ApiControllerAdvice.java @@ -0,0 +1,80 @@ +package org.haedal.zzansuni.global.api; + +import io.jsonwebtoken.JwtException; +import lombok.extern.slf4j.Slf4j; +import org.haedal.zzansuni.core.api.ApiResponse; +import org.haedal.zzansuni.core.api.ErrorCode; +import org.haedal.zzansuni.global.exception.UnauthorizedException; +import org.slf4j.MDC; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.NoSuchElementException; + +@RestControllerAdvice +@Slf4j +public class ApiControllerAdvice { + + + + /** + * http status: 400 AND result: FAIL + * 잘못된 요청 + */ + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResponse illegalArgumentException(IllegalArgumentException e) { + return ApiResponse.fail(ErrorCode.COMMON_INVALID_PARAMETER); + } + + /** + * http status: 400 AND result: FAIL + * 잘못된 요청 + */ + @ExceptionHandler + @ResponseStatus(HttpStatus.BAD_REQUEST) + public ApiResponse illegalStateException(IllegalStateException e) { + return ApiResponse.fail(ErrorCode.COMMON_INVALID_PARAMETER); + } + + /** + * http status: 404 AND result: FAIL + * 존재하지 않는 엔티티 + */ + @ExceptionHandler + @ResponseStatus(HttpStatus.NOT_FOUND) + public ApiResponse noSuchElementException(NoSuchElementException e) { + return ApiResponse.fail(ErrorCode.COMMON_ENTITY_NOT_FOUND); + } + + + /** + * http status: 401 AND result: FAIL + * 인증 실패 + */ + @ExceptionHandler + @ResponseStatus(HttpStatus.UNAUTHORIZED) + public ApiResponse onUnauthorizedException(UnauthorizedException e) { + return ApiResponse.fail("UNAUTHORIZED", e.getMessage()); + } + + + + /** + * http status: 500 AND result: FAIL + * 시스템 예외 상황. 집중 모니터링 대상 + */ + @ExceptionHandler + @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) + public ApiResponse onException(Exception e) { + String eventId = MDC.get(CommonHttpRequestInterceptor.HEADER_REQUEST_UUID_KEY); + log.error("eventId = {} ", eventId, e); + return ApiResponse.fail(ErrorCode.COMMON_SYSTEM_ERROR); + } + + + + +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/exception/UnauthorizedException.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/exception/UnauthorizedException.java new file mode 100644 index 0000000..1401f96 --- /dev/null +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/exception/UnauthorizedException.java @@ -0,0 +1,7 @@ +package org.haedal.zzansuni.global.exception; + +public class UnauthorizedException extends RuntimeException{ + public UnauthorizedException(String message) { + super(message); + } +} diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/jwt/JwtUtils.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/jwt/JwtUtils.java index 9155240..0f33a55 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/jwt/JwtUtils.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/jwt/JwtUtils.java @@ -1,9 +1,9 @@ package org.haedal.zzansuni.global.jwt; import io.jsonwebtoken.Claims; -import io.jsonwebtoken.JwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; +import org.haedal.zzansuni.global.exception.UnauthorizedException; import org.haedal.zzansuni.global.security.Role; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; @@ -60,7 +60,7 @@ public boolean validateToken(String rawToken) { public String reissueAccessToken(JwtToken.ValidToken refreshToken) { Claims claims = extractClaims(refreshToken.getValue()); if (claims.get(IS_ACCESS_TOKEN, Boolean.class)) { - throw new JwtException("RefreshToken이 유효하지 않습니다."); + throw new UnauthorizedException("RefreshToken이 유효하지 않습니다."); } JwtUser jwtUser = claimsToJwtUser(claims); return generateToken(jwtUser, true); diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/security/JwtProvider.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/security/JwtProvider.java index b0a1a1c..1cf4f2b 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/security/JwtProvider.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/security/JwtProvider.java @@ -1,7 +1,7 @@ package org.haedal.zzansuni.global.security; -import io.jsonwebtoken.JwtException; import lombok.RequiredArgsConstructor; +import org.haedal.zzansuni.global.exception.UnauthorizedException; import org.haedal.zzansuni.global.jwt.JwtToken; import org.haedal.zzansuni.global.jwt.JwtUser; import org.haedal.zzansuni.global.jwt.JwtUtils; @@ -32,7 +32,7 @@ public Authentication authenticate(Authentication authentication) throws Authent // 토큰을 검증하는 단계 if(!jwtUtils.validateToken(token)){ - throw new JwtException("유효하지 않은 토큰입니다."); + throw new UnauthorizedException("유효하지 않은 토큰입니다."); } JwtUser jwtUser = jwtUtils.getJwtUser(JwtToken.ValidToken.of(token)); Set authorities = Set.of(new SimpleGrantedAuthority(jwtUser.getRole().name())); diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/security/WebSecurityConfig.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/security/WebSecurityConfig.java index 64d1a98..418185b 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/security/WebSecurityConfig.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/global/security/WebSecurityConfig.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.RequiredArgsConstructor; +import org.haedal.zzansuni.core.api.ApiResponse; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; @@ -75,20 +76,20 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { */ http.exceptionHandling((exception) -> exception .authenticationEntryPoint((request, response, authException) -> { -// var errorResponse = ErrorResponse.of("권한이 없습니다."); -// var json = objectMapper.writeValueAsString(errorResponse); + var errorResponse = ApiResponse.fail("UNAUTHORIZED", "인증이 필요합니다."); + var json = objectMapper.writeValueAsString(errorResponse); response.setStatus(401); response.setContentType(MediaType.APPLICATION_JSON_VALUE); -// response.getWriter().write(json); + response.getWriter().write(json); response.getWriter().flush(); }) .accessDeniedHandler((request, response, accessDeniedException) -> { -// var errorResponse = ErrorResponse.of("권한이 없습니다."); -// var json = objectMapper.writeValueAsString(errorResponse); + var errorResponse = ApiResponse.fail("ACCESS_DENIED", "권한이 없습니다."); + var json = objectMapper.writeValueAsString(errorResponse); response.setStatus(403); response.setContentType(MediaType.APPLICATION_JSON_VALUE); -// response.getWriter().write(json); + response.getWriter().write(json); response.getWriter().flush(); }) ); diff --git a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/user/UserReaderImpl.java b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/user/UserReaderImpl.java index 97d5360..d3e7933 100644 --- a/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/user/UserReaderImpl.java +++ b/zzansuni-api-server/app/src/main/java/org/haedal/zzansuni/infrastructure/user/UserReaderImpl.java @@ -6,6 +6,7 @@ import org.haedal.zzansuni.domain.user.UserReader; import org.springframework.stereotype.Component; +import java.util.NoSuchElementException; import java.util.Optional; @Component @@ -15,7 +16,7 @@ public class UserReaderImpl implements UserReader { @Override public User getById(Long id) { - return userRepository.findById(id).orElseThrow(EntityNotFoundException::new); + return userRepository.findById(id).orElseThrow(NoSuchElementException::new); } @Override