1. 커스텀 어노테이션 도입
모든 API에서 동일한 코드가 반복되는걸 막기 위해, 커스텀 어노테이션을 만들어서 파라미터에서 사용자 정보 또는 토큰 정보를 가져올 수 있도록 하는 방법
2. Argument Resolver
2.1 Argument Resolver란?
Argument Resolver는 API 엔드포인트로 인입된 데이터를 가공 및 바인딩 할 때 사용하는 객체
- http body 또는 url parameter로 넘어오는 데이터들은, @ReqeustBody와@RequestParam 등으로 바인딩이 가능하지만, http header, 쿠키, 세션 등으로 전달되는 데이터인 경우에는 Argument Resolver를 이용할 수 있음.
💡 Argument Resolver는 대표적으로 세션에서 로그인한 사용자의 정보를 얻거나, 헤더로 전달되는 인증 정보에서 토큰의 정보 및 사용자의 정보를 얻을 때 사용
2.2 Argument Resolver 호출 시기
Argument Resolver가 호출되는 시기는 handler adapter를 찾은 이후 Argument Resolver가 처리되고, 이후 Handler를 실행
💡 즉, 컨트롤러 method → Argument Resolver 처리 → 컨트롤러 method 실행
3. 토큰 추출 커스텀 어노테이션 만들기
3.1 어노테이션 선언
@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 | 컴파일 이후 어노테이션 정보 소멸 |
3.2 Argument Resolver 구현
@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 (커스텀 어노테이션) 존재 여부
- parameter 타입이 String.class에 해당 여부
- resloveArgument() : supportsParameter() 가 true값을 return하면 실행되는 메서드, 파라미터에 전달할 객체를 return
3.3 Resolver 추가
구현한 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에 구현체를 추가
3.4 사용 방식
@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을 추출하여 반환
참고
[JWT] 세션 의존성 제거하기 - 커스텀 어노테이션 활용
[JWT] 세션 의존성 제거하기 - 커스텀 어노테이션 활용
토큰 기반 인증 방식으로 소셜 로그인 및 회원가입 기능을 구현했다.그런데 구현하고 보니, 토큰을 세션에 저장하고 세션에서 해당 토큰을 꺼내서현재 로그인한 사용자를 가져오도록 구현을 했
velog.io
'Dev > SpringBoot' 카테고리의 다른 글
카카오페이 단건 결제 구현하기 (0) | 2025.02.10 |
---|---|
SSE로 푸시 알림 기능 구현하기 (0) | 2025.02.10 |
카카오 로그인 구현하기(3) - Redis + 액세스 토큰 재발급하기 (0) | 2025.02.10 |
카카오 로그인 구현하기(2) - JWT + Spring Security (0) | 2025.02.10 |
카카오 로그인 구현하기(1) - 카카오 로그인 (0) | 2025.02.10 |