오답노트

[Spring] Interceptor 본문

Java/Spring

[Spring] Interceptor

권멋져 2023. 7. 14. 13:57

Interceptor

Intercepter는 FIlter와 매우 유사한 형태로 존재하지만, 차이점은 Spring Context에 등록된다는 점이다.

AOP와 유사한 기능을 제공 할 수 있고, 주로 인증 단계를 처리하거나, Logging을 하는데 사용한다.

이를 전/후처리 함으로써 Service business logic과 분리 시킨다.

 

import com.example.interceptor.annotation.Auth;
import com.example.interceptor.exception.AuthException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String url = request.getRequestURI();

        URI uri = UriComponentsBuilder.fromUriString(request.getRequestURI()).query(request.getQueryString()).build().toUri();

        log.info("req url : {}",url);
        boolean hasAnnotation = checkAnnotation(handler, Auth.class);
        log.info("has Annotation : {}",hasAnnotation);

        // 나의 서버는 모두 public으로 동작하는데
        // 단, Auth 권한을 가진 요청에 대해서는 ...
        if(hasAnnotation){
            // 권한 체크
            String query = uri.getQuery();
            log.info("query : {}",query);
            if(query.equals("name=steve")){
                return true;
            }

            throw new AuthException();
        }

        return true;
    }

    private boolean checkAnnotation(Object handler, Class clazz){
        // resorce, js, html
        if( handler instanceof ResourceHttpRequestHandler){
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        if(null != handlerMethod.getMethodAnnotation(clazz) || null != handlerMethod.getBeanType().getAnnotation(clazz)){
            return true;
        }

        return false;
    }
}

HandlerInterceptor 인터페이스를 상속받아 Interceptor 클래스를 생성한다.

preHandle 를 Override 하여 권한과 같이 체크할 항목에 대한 로직을 구현하고, 절차를 다 정상적으로 수행했으면 true, 아니면 false를 반환한다.

 

import com.example.interceptor.Interceptor.AuthInterceptor;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@RequiredArgsConstructor
public class MvcConfig implements WebMvcConfigurer {

    private final AuthInterceptor authInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor).addPathPatterns("/api/private/*");
    }
}

그리고 WebMvcConfigurer 를 상속 받는 Config 클래스를 만들어 위에서 만든 Interceptor 클래스를 등록한다.

Config 클래스에 Interceptor 멤버 변수를 선언하고 addInterceptors를 Override하여 위에서 만든 Interceptor클래스가 어떤 주소에서 동작하게 할지 설정한다. 

'Java > Spring' 카테고리의 다른 글

[Spring] Server to Server  (0) 2023.07.14
[Spring] 비동기 처리 (Async)  (0) 2023.07.14
[Spring] Filter  (0) 2023.07.14
[Spring] Exception과 Validation  (0) 2023.07.14
[Spring] Exception  (0) 2023.07.14