Spring Boot | HandlerMethodArgumentResolver로 Authentication 정보 간단하게 받기
Spring Security를 사용하면 인증된 사용자의 정보를
Authentication
객체를 통해 받을 수 있다.Authentication
은SecurityContextHolder
에 저장되어 있음
HandlerMethodArgumentResolver
HandlerMethodArgumentResolver
인터페이스는 두 개의 메서드를 구현하도록 하고 있다.
supportsParameter()
: 주어진 메서드 파라미터를 이 reolver로 지원할지 여부resolveArgument()
: 파라미터에 전달할 객체를 생성
boolean supportsParameter(MethodParameter parameter)
Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory)
Authentication
의 값(username, details)를 계속 사용해야 하는데 해당 코드가 반복되므로 HandlerMethodArgumentResolver를 통해 간단히 애노테이션만으로 처리하면 좋을 것 같았다!
1. 애노테이션 만들기
@AuthUser
라는 애노테이션을 만든다.@Target(ElementType.PARAMETER)
는 파라미터에 해당 애노테이션을 사용할 수 있다는 뜻이다. 여러 타겟을 입력할 수 있다.
애노테이션을 만들 때는 클래스 선언부에 class
대신 @interface
를 사용한다.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface AuthUser {
}
2. HandlerMethodArgumentResolver 구현체 작성
HandlerMethodArgumentResolver
를 상속받는 구현체를 작성한다.
위에서 알아본 두 개의 메서드를 오버라이딩하여 원하는 값을 바인딩 하면 된다!
@Component
public class AuthenticationArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return false;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return null;
}
}
supportsParameter()
에서는 해당 파라미터에 위에서 만든 @AuthUser
애노테이션이 사용됐는지, 그리고 해당 파라미터가 RegisterDto
클래스가 맞는지 확인한다.
@Override
public boolean supportsParameter(MethodParameter parameter) {
final boolean isRegUserAnnotation = parameter.getParameterAnnotation(AuthUser.class) != null;
final boolean isRegisterDto = parameter.getParameterType().equals(RegisterDto.class);
return isRegUserAnnotation && isRegisterDto;
}
supportsParameter()
의 반환 값이 true
라면 해당 메서드가 실행된다.SecurityContextHolder
에 저장된 Authentication
을 얻어 원하는 값들을 정제하고 new RegisterDto()
에 바인딩하여 반환하도록 작성했다. 이제 메서드의 파라미터에 someMethod(@AuthUser RegisterDto registerDto)
이런식으로 작성하면 간단하게 원하는 값을 얻을 수 있게된다.
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
// 생략..
return new RegisterDto(/* 생략.. */);
}
return null;
}
3. argumentResolver 등록
스프링 부트에서 해당 resolver를 인식할 수 있도록 등록 한다.HandlerMethodArgumentResolver
는 항상 WebMvcConfiguerer
의 addArgumentResolvers()
를 통해 추가해야 한다.
@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final AuthenticationArgumentResolver authenticationArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(authenticationArgumentResolver);
}
}
사용해보기!
이렇게 메서드의 파라미터에 @AuthUser
애노테이션을 붙이기만 하면 해당 파라미터에 데이터가 바인딩된다.
@PostMapping()
public Response (@AuthUser RegisterDto registerDto,
@RequestBody SaveDto saveDto) {
// 생략
}
참고
- 이동욱 저 스프링 부트와 AWS로 혼자 구현하는 웹 서비스 195p~199p