모든 API에서 동일한 코드가 반복되는걸 막기 위해, 커스텀 어노테이션을 만들어서 파라미터에서 사용자 정보 또는 토큰 정보를 가져올 수 있도록 하는 방법
Argument Resolver는 API 엔드포인트로 인입된 데이터를 가공 및 바인딩 할 때 사용하는 객체
@ReqeustBody와@RequestParam 등으로 바인딩이 가능하지만, http header, 쿠키, 세션 등으로 전달되는 데이터인 경우에는 Argument Resolver를 이용할 수 있음.💡
Argument Resolver는 대표적으로 세션에서 로그인한 사용자의 정보를 얻거나, 헤더로 전달되는 인증 정보에서 토큰의 정보 및 사용자의 정보를 얻을 때 사용
Argument Resolver가 호출되는 시기는 handler adapter를 찾은 이후 Argument Resolver가 처리되고, 이후 Handler를 실행
💡 즉, 컨트롤러 method → Argument Resolver 처리 → 컨트롤러 method 실행
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface GetToken {
}
@Target
| 이름 | 설명 |
|---|---|
| PACKAGE | 패키지 선언 시 |
| TYPE | 타입(클래스, 인터페이스, enum) 선언 시 |
| CONSTUCTOR | 생성자 선언 시 |
| FIELD | enum 상수를 포함한 멤버변수 선언 시 |
| METHOD | 메소드 선언시 |
| ANNOTATION_TYPE | 어노테이션 타입 선언 시 |
| LOCAL_VARIABLE | 지역변수 선언 시 |
| PARAMETER | 파라미터 선언 시 |
| TYPE_PARAMETER | 파라미터 타입 선언 시 |
@Retention
| 이름 | 설명 |
|---|---|
| RUNTIME | 컴파일 이후에도 참조 가능 |
| CLASS | 클래스를 참조할 때 까지 유효 |
| SOURCE | 컴파일 이후 어노테이션 정보 소멸 |
@Slf4j
@Component
@RequiredArgsConstructor
public class GetTokenArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
boolean isString = parameter.getParameterType().equals(String.class);
boolean isGetToken = parameter.hasParameterAnnotation(GetToken.class);
return isString && isGetToken;
}
@Override
public Object resolveArgument(
MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
String refreshToken = webRequest.getHeader("Authorization");
if (refreshToken == null || refreshToken.isEmpty()) {
throw new GlobalException(GlobalErrorCode._UNAUTHORIZED);
}
if (!refreshToken.startsWith("Bearer ")) {
throw new GlobalException(GlobalErrorCode.AUTH_INVALID_TOKEN);
}
return refreshToken.substring(7);
}
}
supportsParameter() 컨트롤러의 method에 존재하는 파라미터들에 대해서 검사하여, 적용 여부를 판단GetToken.class (커스텀 어노테이션) 존재 여부resloveArgument() supportsParameter() 가 true값을 return하면 실행되는 메서드 파라미터에 전달할 객체를 return구현한 Resolver를 등록해줘야 동작을 함
@RequiredArgsConstructor
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final GetTokenArgumentResolver getTokenArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(getTokenArgumentResolver);
}
}
WebMvcConfigurer의 구현체를 만들고 addArgumentResolvers 메서드를 오버라이딩 하여 List에 구현체를 추가
@Operation(summary = "토큰 재발급", description = "access 토큰이 만료된 경우 refresh 토큰을 통해 토큰을 재발급 합니다.")
@GetMapping("/kakao/reissue")
public ApiResponse<AuthResponseDTO.AuthToken> reissueToken(@GetToken String refreshToken) {
return ApiResponse.onSuccess("토큰 재발급 성공", authService.reissueToken(refreshToken));
}
컨트롤러 method에 파라미터에 적용
resolver가 인증 헤더에서 refresh Token을 추출하여 반환