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