알고리즘 문제 출제 사이트를 구현하면서 인증된 사용자의 정보를 인가하는 로직이 매 페이지마다 필요했다.
이 로직을 모든 서비스 코드에서 작성하게 되면 너무 많은 코드 중복이 생긴다.
그래서 ArgumentResolver를 사용해 사용자 인증처리 중복 코드를 제거하였다.
argumentResolver를 구현하기 전에 spring mvc가 어떻게 request를 처리하는지 알아야 한다.
- client가 웹 브라우저를 통해 dispatcherServlet으로 request를 보낸다.
- dispatcherServlet은 HandlerMapping에게 요청을 처리할 핸들러를 찾도록 위임한다.
- RequestMapping으로 구현한 API 검색(RequestMappingHandlerAdapter)
- 찾은 경우 Interceptor 처리 -> ArgumentResolver 처리 -> MessageConverter 처리를 한다.
- Controller Invoke
Strategy interface for resolving method parameters into argument values in the context of a given request.
적용 코드
@Component
public class CustomMemberResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().equals(Member.class);
}
@Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getPrincipal() instanceof CustomMemberDetails) {
CustomMemberDetails customMemberDetails = (CustomMemberDetails) authentication.getPrincipal();
return customMemberDetails.getMember();//Member 객체 리턴
}
return new EntityNotFoundException();
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new CustomMemberResolver());//Resolver 추가
}
}
@Target(ElementType.PARAMETER) // --- 1
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthUser {
//어노테이션 추가
}
공통로직을 추출한 후 다음과 같이 컨트롤러에서 사용해주었다.
@PostMapping("/save")//질문 게시글 작성
public ResponseEntity save(@RequestBody QuestionSaveDTO saveForm,@AuthUser Member member)
@DeleteMapping("/{questionId}")
public ResponseEntity deleteQuestion(@PathVariable("questionId") long questionId, @AuthUser Member member)