diff --git a/backend/src/main/java/kr/momo/config/WebConfig.java b/backend/src/main/java/kr/momo/config/WebConfig.java index 35d0d078c..df00fa4b1 100644 --- a/backend/src/main/java/kr/momo/config/WebConfig.java +++ b/backend/src/main/java/kr/momo/config/WebConfig.java @@ -1,20 +1,33 @@ package kr.momo.config; import java.util.List; +import kr.momo.config.interceptor.JwtInterceptor; +import kr.momo.config.interceptor.LoggingInterceptor; import kr.momo.controller.auth.AuthArgumentResolver; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration @RequiredArgsConstructor public class WebConfig implements WebMvcConfigurer { + private static final String BASE_URL = "/api/v1/**"; + private final AuthArgumentResolver authArgumentResolver; + private final JwtInterceptor jwtInterceptor; + private final LoggingInterceptor loggingInterceptor; @Override public void addArgumentResolvers(List resolvers) { resolvers.add(authArgumentResolver); } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(jwtInterceptor).addPathPatterns(BASE_URL).order(1); + registry.addInterceptor(loggingInterceptor).addPathPatterns(BASE_URL).order(2); + } } diff --git a/backend/src/main/java/kr/momo/config/filter/FilterConfig.java b/backend/src/main/java/kr/momo/config/filter/FilterConfig.java deleted file mode 100644 index fbdec8729..000000000 --- a/backend/src/main/java/kr/momo/config/filter/FilterConfig.java +++ /dev/null @@ -1,29 +0,0 @@ -package kr.momo.config.filter; - -import jakarta.servlet.Filter; -import lombok.RequiredArgsConstructor; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -@RequiredArgsConstructor -public class FilterConfig { - - private static final String BASE_URL = "/api/v1/*"; - private static final int FIRST_ORDER = 0; - - private final TraceIdGenerator traceIdGenerator; - private final LogGenerator logGenerator; - - @Bean - public FilterRegistrationBean logFilter() { - FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>(); - - filterRegistrationBean.setFilter(new LogFilter(traceIdGenerator, logGenerator)); - filterRegistrationBean.addUrlPatterns(BASE_URL); - filterRegistrationBean.setOrder(FIRST_ORDER); - - return filterRegistrationBean; - } -} diff --git a/backend/src/main/java/kr/momo/config/filter/LogFilter.java b/backend/src/main/java/kr/momo/config/filter/LogFilter.java deleted file mode 100644 index e66464b48..000000000 --- a/backend/src/main/java/kr/momo/config/filter/LogFilter.java +++ /dev/null @@ -1,42 +0,0 @@ -package kr.momo.config.filter; - -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.slf4j.MDC; -import org.slf4j.MDC.MDCCloseable; - -@Slf4j -@RequiredArgsConstructor -public class LogFilter implements Filter { - - public static final String TRACE_ID = "traceId"; - - private final TraceIdGenerator traceIdGenerator; - private final LogGenerator logGenerator; - - @Override - public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) - throws IOException, ServletException { - - HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; - HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; - - String traceId = traceIdGenerator.generateShortUuid(); - - try (MDCCloseable ignored = MDC.putCloseable(TRACE_ID, traceId)) { - logGenerator.logRequest(traceId, httpRequest); - long startTime = System.currentTimeMillis(); - filterChain.doFilter(servletRequest, servletResponse); - long duration = System.currentTimeMillis() - startTime; - logGenerator.logResponse(traceId, duration, httpRequest, httpResponse); - } - } -} diff --git a/backend/src/main/java/kr/momo/config/interceptor/JwtInterceptor.java b/backend/src/main/java/kr/momo/config/interceptor/JwtInterceptor.java new file mode 100644 index 000000000..034a3e040 --- /dev/null +++ b/backend/src/main/java/kr/momo/config/interceptor/JwtInterceptor.java @@ -0,0 +1,51 @@ +package kr.momo.config.interceptor; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.util.Arrays; +import java.util.Optional; +import kr.momo.service.auth.JwtManager; +import lombok.RequiredArgsConstructor; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +@Component +@RequiredArgsConstructor +public class JwtInterceptor implements HandlerInterceptor { + + public static final String USER_INFO = "userInfo"; + + private static final String ANONYMOUS = "ANONYMOUS"; + private static final String ACCESS_TOKEN = "ACCESS_TOKEN"; + + private final JwtManager jwtManager; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + Cookie[] cookies = request.getCookies(); + String userInfo = getCookieValue(cookies).orElse(ANONYMOUS); + if (isLoginUser(userInfo)) { + userInfo = String.valueOf(jwtManager.extract(userInfo)); + } + MDC.put(USER_INFO, userInfo); + + return true; + } + + private Optional getCookieValue(Cookie[] cookies) { + if (cookies == null) { + return Optional.empty(); + } + + return Arrays.stream(cookies) + .filter(cookie -> ACCESS_TOKEN.equals(cookie.getName())) + .map(Cookie::getValue) + .findFirst(); + } + + private boolean isLoginUser(String token) { + return !ANONYMOUS.equals(token); + } +} diff --git a/backend/src/main/java/kr/momo/config/filter/LogGenerator.java b/backend/src/main/java/kr/momo/config/interceptor/LogGenerator.java similarity index 53% rename from backend/src/main/java/kr/momo/config/filter/LogGenerator.java rename to backend/src/main/java/kr/momo/config/interceptor/LogGenerator.java index fca91f4fe..e3bfbad6f 100644 --- a/backend/src/main/java/kr/momo/config/filter/LogGenerator.java +++ b/backend/src/main/java/kr/momo/config/interceptor/LogGenerator.java @@ -1,27 +1,39 @@ -package kr.momo.config.filter; +package kr.momo.config.interceptor; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.slf4j.MDC; import org.springframework.stereotype.Component; @Slf4j @Component +@RequiredArgsConstructor public class LogGenerator { public void logRequest(String traceId, HttpServletRequest request) { String httpMethod = request.getMethod(); String requestURI = request.getRequestURI(); - String remoteAddr = request.getRemoteAddr(); + String userInfo = MDC.get(JwtInterceptor.USER_INFO); - log.info("REQUEST [{}][{} {}][{}]", traceId, httpMethod, requestURI, remoteAddr); + log.info("REQUEST [{}][USERID:{}][{} {}]", traceId, userInfo, httpMethod, requestURI); } public void logResponse(String traceId, long duration, HttpServletRequest request, HttpServletResponse response) { String httpMethod = request.getMethod(); String requestURI = request.getRequestURI(); + String userInfo = MDC.get(JwtInterceptor.USER_INFO); int status = response.getStatus(); - log.info("RESPONSE [{}][{} {}][{} ms][Status: {}]", traceId, httpMethod, requestURI, duration, status); + log.info( + "RESPONSE [{}][USERID:{}][{} {}][{} ms][Status: {}]", + traceId, + userInfo, + httpMethod, + requestURI, + duration, + status + ); } } diff --git a/backend/src/main/java/kr/momo/config/interceptor/LoggingInterceptor.java b/backend/src/main/java/kr/momo/config/interceptor/LoggingInterceptor.java new file mode 100644 index 000000000..63283c378 --- /dev/null +++ b/backend/src/main/java/kr/momo/config/interceptor/LoggingInterceptor.java @@ -0,0 +1,41 @@ +package kr.momo.config.interceptor; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +@Slf4j +@RequiredArgsConstructor +@Component +public class LoggingInterceptor implements HandlerInterceptor { + + public static final String TRACE_ID = "traceId"; + private static final String START_TIME = "startTime"; + + private final TraceIdGenerator traceIdGenerator; + private final LogGenerator logGenerator; + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { + String traceId = traceIdGenerator.generateShortUuid(); + MDC.put(TRACE_ID, traceId); + logGenerator.logRequest(traceId, request); + request.setAttribute(START_TIME, System.currentTimeMillis()); + return true; + } + + @Override + public void afterCompletion( + HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex + ) { + long startTime = (Long) request.getAttribute(START_TIME); + long duration = System.currentTimeMillis() - startTime; + String traceId = MDC.get(TRACE_ID); + logGenerator.logResponse(traceId, duration, request, response); + MDC.clear(); + } +} diff --git a/backend/src/main/java/kr/momo/config/filter/TraceIdGenerator.java b/backend/src/main/java/kr/momo/config/interceptor/TraceIdGenerator.java similarity index 86% rename from backend/src/main/java/kr/momo/config/filter/TraceIdGenerator.java rename to backend/src/main/java/kr/momo/config/interceptor/TraceIdGenerator.java index 48cf5494d..9426b67a3 100644 --- a/backend/src/main/java/kr/momo/config/filter/TraceIdGenerator.java +++ b/backend/src/main/java/kr/momo/config/interceptor/TraceIdGenerator.java @@ -1,4 +1,4 @@ -package kr.momo.config.filter; +package kr.momo.config.interceptor; import java.util.UUID; import org.springframework.stereotype.Component; diff --git a/backend/src/main/java/kr/momo/exception/GlobalExceptionHandler.java b/backend/src/main/java/kr/momo/exception/GlobalExceptionHandler.java index 88a7d5780..2ee59d6d5 100644 --- a/backend/src/main/java/kr/momo/exception/GlobalExceptionHandler.java +++ b/backend/src/main/java/kr/momo/exception/GlobalExceptionHandler.java @@ -1,6 +1,6 @@ package kr.momo.exception; -import kr.momo.config.filter.LogFilter; +import kr.momo.config.interceptor.LoggingInterceptor; import lombok.extern.slf4j.Slf4j; import org.slf4j.MDC; import org.springframework.http.HttpStatus; @@ -20,7 +20,7 @@ public class GlobalExceptionHandler { @ExceptionHandler public ProblemDetail handleMomoException(MomoException ex) { - String traceId = MDC.get(LogFilter.TRACE_ID); + String traceId = MDC.get(LoggingInterceptor.TRACE_ID); log.warn(EXCEPTION_LOG_FORMAT, traceId, ex); ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(ex.httpStatus(), ex.message()); @@ -29,7 +29,7 @@ public ProblemDetail handleMomoException(MomoException ex) { @ExceptionHandler public ProblemDetail handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) { - String traceId = MDC.get(LogFilter.TRACE_ID); + String traceId = MDC.get(LoggingInterceptor.TRACE_ID); log.warn(EXCEPTION_LOG_FORMAT, traceId, ex); ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail( @@ -40,7 +40,7 @@ public ProblemDetail handleMethodArgumentNotValidException(MethodArgumentNotVali @ExceptionHandler public ProblemDetail handleInternalException(Exception ex) { - String traceId = MDC.get(LogFilter.TRACE_ID); + String traceId = MDC.get(LoggingInterceptor.TRACE_ID); log.error(EXCEPTION_LOG_FORMAT, traceId, ex); return ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, INTERNAL_SERVER_ERROR_MESSAGE);