커스텀 어노테이션으로 유저 정보 가져오기

노을·2025년 5월 24일
0

✅ 커스텀 어노테이션 사용 이유

너디너리 해커톤에서 로그인을 구현했는데 빠르게 개발해야 하다보니 스프링 시큐리티를 사용하지 않고 개발했다. 그리고 클라이언트는 다음과 같이 access token을 헤더에 담아 요청해야 했다.

Authorization: Bearer {access token}


스프링 시큐리티를 사용하면 컨트롤러에서 인증 객체를 바로 받아올 수 있지만, 난 사용하지 않았기 때문에 일일히 헤더에 있는 토큰을 가져와서 검증하고 파싱해서 시크릿을 얻어야 한다.


매번 이 과정을 하는 게 귀찮으니 커스텀 어노테이션을 만들어서 사용했다.
그리고 스웨거에서는 제외 시키기 위해 @Parameter(hidden = true)을 해주었다.

@PostMapping("/register")
public ResponseEntity<FoodRegisterResponse> registerFood(
        @Parameter(hidden = true) @JwtValidation Long userId //@JwtValidation 사용
) {
    ...
}



✅ 커스텀 어노테이션 만들기

1. 커스텀 어노테이션 선언

@Target(ElementType.PARAMETER) //메서드의 파라미터에만 적용 가능
@Retention(RetentionPolicy.RUNTIME) //런타임에도 유지
@Documented //자바독에 포함
public @interface JwtValidation {
}

2. 리졸버 만들기

@Component
@RequiredArgsConstructor
public class JwtArgumentResolver implements HandlerMethodArgumentResolver {
	private final JwtUtil jwtUtil;

	//적용 여부 판단
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return parameter.hasParameterAnnotation(JwtValidation.class) &&
			parameter.getParameterType().equals(Long.class);
	}

	//user id 추출
	@Override
	public Object resolveArgument(MethodParameter parameter,
		ModelAndViewContainer mavContainer,
		NativeWebRequest webRequest,
		WebDataBinderFactory binderFactory) {

		String authHeader = webRequest.getHeader("Authorization");
		if (authHeader == null || !authHeader.startsWith("Bearer ")) {
			throw new UserException(ErrorCode.INVALID_TOKEN);
		}

		String token = authHeader.substring(7);
		if (!jwtUtil.validateToken(token)) {
			throw new UserException(ErrorCode.INVALID_TOKEN);
		}
		return jwtUtil.getUserIdFromToken(token);
	}
}

HandlerMethodArgumentResolver 인터페이스를 구현해 리졸버를 만들어준다.

HandlerMethodArgumentResolver는 Spring MVC에서 컨트롤러 메서드의 파라미터에 값을 바인딩해주는 인터페이스이다.

스프링 내장 리졸버들

어노테이션처리 클래스
@RequestParamRequestParamMethodArgumentResolver
@RequestBodyRequestResponseBodyMethodProcessor
@PathVariablePathVariableMethodArgumentResolver
@RequestHeaderRequestHeaderMethodArgumentResolver

3. 리졸버 스프링 컨텍스트에 등록

    @Configuration
    @RequiredArgsConstructor
    public class WebConfig implements WebMvcConfigurer {
    	private final JwtArgumentResolver jwtArgumentResolver;
    
    	@Override
    	public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    		resolvers.add(jwtArgumentResolver);
    	}
    }

이렇게 하면 컨트롤러 메서드 실행 직전 리졸버가 파라미터를 바인딩 해준다.


✔️ 동작 흐름

1. HTTP 요청 도착
2. DispatcherServlet이 컨트롤러 파라미터 조사
3. supportsParameter() → 어노테이션 붙었는지 확인
4. resolveArgument() → 토큰 검증 → userId 리턴
5. userId를 컨트롤러 메서드에 자동 주입
profile
진짜를 알면 곁가지를 몰라도 된다

0개의 댓글