ArgumentResolver

ArgumentResolver 에 관한 설명은 이 글을 참고한다.

기존 Interceptor 를 사용하는 방식도 괜찮지만 이번엔 ArgumentResolver 를 사용해보자.

커스텀 애노테이션 @Login 을 만들고 이 애노테이션이 붙은 메서드만 인증 로직을 적용할 것이다.

 

PostController

커스텀 애노테이션 @Login 이 붙은 컨트롤러를 만든다. 이 컨트롤러는 userSession 의 hello 필드의 값을 반환한다.

@GetMapping("/hello")
public String hello(@Login UserSession userSession) {
    return userSession.getHello();
}

 

Login

커스텀 애노테이션을 만드는법은 생각보다 간단하다.

아래처럼 설정만하면 된다.

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Login {
}

ㄴ @Target(ElementType.PARAMETER)

우리가 만들 커스텀 애노테이션이 동작할 범위를 정한다.

파라미터에만 사용할 수 있도록 설정한다.

ㄴ @Retention(RetentionPolicy.RUNTIME)

우리가 만들 커스텀 애노테이션의 라이프 사이클을 정한다.

리플렉션 등을 활용할 수 있도록 런타임까지 애노테이션 정보가 남아있도록 설정한다.

 

UserSession

@Getter
public class UserSession {

    private final String hello;

    public UserSession(String hello) {
        this.hello = hello;
    }
}

 

AuthResolver

@Login 애노테이션이 달려있는지 확인하고 달려있다면 인증을 진행하는 ArgumentResolver 를 만든다.

public class AuthResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(Login.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        String authorization = webRequest.getHeader("Authorization");
        if (authorization == null || authorization.isBlank()) {
            throw new UnauthorizedException();
        }
        return new UserSession("Hello World");
    }
}

1. supportsParameter()

ㄴhasParameterAnnotation()

해당 애노테이션이 달려있는지 확인하고 달려있을 시 resolveArgument() 메서드를 실행한다.

여기서는 @Login 을 체크한다.

2. resolveArgument()

우선은 간단하게 Authorization 헤더를 갖고있는지, 빈값이 아닌지만 체크한다.

갖고 있는 경우 hello 필드에 "Hello World" 값을 갖는 UserSession 객체를 만든다.

 

WebMvcConfig

AuthResolver 를 사용하기 위해 WebMvcConfig 에 추가한다.

기존의 Interceptor 를 사용하던 방식은 당분간 사용하지 않을것이므로 WebMvcConfig 에서 주석처리한다.

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

//    @Override
//    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(new AuthInterceptor())
//            .excludePathPatterns("/error", "/favicon.ico");
//    }

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new AuthResolver());
    }
}

ㄴaddArgumentResolvers

위 메서드를 오버라이드 해서 우리가 만든 AuthResolver 를 추가한다.

 


PostControllerTest

Authorization 헤더를 추가하면 Hello World 를 출력하는 테스트를 작성한다.

@DisplayName("/hello 요청시 Hello World 를 출력한다.")
@Test
void hello() throws Exception {
    mockMvc.perform(
        MockMvcRequestBuilders.get("/hello")
            .header("Authorization","midcon")
        )
        .andExpect(status().isOk())
        .andExpect(content().string("Hello World"))
        .andDo(print());
}

 

테스트는 성공하고 우리가 의도한대로 동작한다.

만약 헤더값을 빼고 테스트를 돌리면 아래와 같이 예외가 터지며 인증이 필요하다는 메시지를 반환할것이다.

 

+ Recent posts