ArgumentResolver등록이 안되는 문제 발생
package org.example.expert.config;
import lombok.RequiredArgsConstructor;
import org.example.expert.domain.common.interceptor.adminCheckInterceptor;
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;
import java.util.List;
@RequiredArgsConstructor
public class WebConfig implements WebMvcConfigurer {
private final adminCheckInterceptor adminCheckInterceptor;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new AuthUserArgumentResolver());
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(adminCheckInterceptor)
.addPathPatterns("/admin/users/*")
.addPathPatterns("/admin/comments/*");
}
}
오류 코드를 봤을 때 resolver.add(A) A에 들어가는 값이 null 값처리가 된다는 문구를 확인하였고 resolver는 아무 문제가 없었다.
한참을 씨름을 하다가 Webconfig 클래스에 @Configuration 어노테이션이 빠져있는 것을 뒤늦게 확인..
붙여주니 정상적으로 잘 돌아갔다. 빠진 것이 없는지 위에서부터 순차적으로 보는 것이 디버깅보다 더 첫번째 인 것 같다.
인터셉터 구현 후 정상 실행이 되는지 테스트를 진행하였고, 로그가 안찍히는 것이 확인이 되었다.
튜터님의 세션 덕분에 필터를 거친 후 인터셉터로 넘어가기 때문에 필터에서 중복되는 것이 있기 때문에 인터셉터에서 확인이 불가능한 것인가 의심할 수 있게 되었다.
jwtFilter에 아니나 다를까 동일한 로직이 실행되고 있었고 그 부분을 주석 처리를 해 다시 확인해 보았다.
그래도 나오지 않았다. 코드를 확인해보니
if(!UserRole.ADMIN.name().equals(role)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "권한이 없습니다");
return false;
}
log.info("접근이 차단되었습니다.");
이후 위 코드를 추가 후 정상 작동하는 것을 확인할 수 있었다..
코드는 문제가 없다. 문제는 나에게 있다.ㅎㅎ
package org.example.expert.domain.common.AOP;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.ContentCachingRequestWrapper;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LoggingAop {
private final ObjectMapper objectMapper;
// .controller.*AdminController.*
//전 후로 로그를 찍어준다.
@Around("execution(* org.example.expert.domain.*.controller.*AdminController.*(..))")
public Object logApi(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
HttpServletResponse response = ((ServletResponseAttributes) ResponseContextHolder.currentResponseAttributes()).getResponse();
ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) request;
Long userId = (Long) request.getAttribute("userId");
LocalDateTime now = LocalDateTime.now();
String requestURI = request.getRequestURI();
String resquestBody = new String(requestWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
log.info("userId = {},Time = {}, URL = {}, body = {}", userId, now, requestURI, resquestBody);
Object result = joinPoint.proceed();
log.info("body = {}", response);
return result;
}
}
최초 앞서 캐싱 필터를 통해 각 응답/요청을 적용 시키고, 적용 시킨 값을 로그에 찍히게 하려하였지만 응답의 바디 값이 계속 비어져 있는 것을 확인 할 수 있었다.
팀원분과 상의하면서 의논해보니 AOP는 Controller → Service → AOP 순으로 실행되기 때문에 저 시점에는 아직 응답이 읽히지 않을 때이기 때문이란 것을 알게 되었다.
따라서 응답값을 따로 빼주는 것이 아닌
package org.example.expert.domain.common.AOP;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.ContentCachingRequestWrapper;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LoggingAop {
private final ObjectMapper objectMapper;
// .controller.*AdminController.*
//전 후로 로그를 찍어준다.
@Around("execution(* org.example.expert.domain.*.controller.*AdminController.*(..))")
public Object logApi(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
ContentCachingRequestWrapper requestWrapper = (ContentCachingRequestWrapper) request;
Long userId = (Long) request.getAttribute("userId");
LocalDateTime now = LocalDateTime.now();
String requestURI = request.getRequestURI();
String resquestBody = new String(requestWrapper.getContentAsByteArray(), StandardCharsets.UTF_8);
log.info("userId = {},Time = {}, URL = {}, body = {}", userId, now, requestURI, resquestBody);
Object result = joinPoint.proceed();
log.info("body = {}", objectMapper.writeValueAsString(result));
return result;
}
}
오브젝트매퍼를 활용해서 메서드의 결과값을 통해 응답값을 출력할 수 있도록 수정하니 잘 작동되는 것을 확인할 수 있었다.
팀원들에게 문제를 공유하고 같이 해결하니 금방할 수 있게 되었다.
J없는 사람은 서러워서 살겠나요 ㅠㅠ 더블제이의 글에 감탄하고 갑니다 ㅠㅠ