스프링의 다양한 기능2(Filter, Interceptor)

이종윤·2022년 1월 21일
0

Spring

목록 보기
7/10

Interceptor

😎🤔🦜
Interceptor 란 Filter 와 매우 유사한 형태로 존재 하지만, 차이점은 Spring Context에 등록 된다.
AOP와 유사한 기능을 제공 할 수 있으며, 주로 인증단계를 처리하거나, Logging를 하는 데에 사용한다.
이를 선/후 처리 함으로써, Service business logic 과 분리 시킨다.

백문이불여일타

인증관리하는 인터셉터 만들어보자

session이나 쿠키를 사용해야하지만... 인터셉터 실습이기 때문에 필드값받아서 확인

@Auth
@RestController
@RequestMapping("/api/private")
public class PrivateController {

    @GetMapping("/hello")
    public String hello() {
        return "private hello";
    }
}
@RestController
@RequestMapping("/api/public")
public class PublicController {

    @GetMapping("/hello")
    public String hello() {
        return "public hello";
    }
}

Private컨트롤러와 Public 컨트롤러를 만들고 Private에는 @Auth를 붇여준다.(인증을 통과해야 컨트롤러에 접근가능하게 할꺼다.)

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Auth {
}

🦜 @Auth 어노테이션 만들어주고

@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        String url = request.getRequestURI();
        log.info("request url : {}", url);

        return false;
    }

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

        //anntation check
        HandlerMethod handlerMethod = (HandlerMethod) handler;

        if (null != handlerMethod.getMethodAnnotation(clazz) || null != handlerMethod.getBeanType().getAnnotation(clazz)) {
            // Auth anntation 이 있을때는 true
            return true;
        }
        return false;
    }
}

🦜 AuthInterceptor 클래스에 조건들을 달아준다.

@Configuration
@RequiredArgsConstructor //fianl로 선언한 객체를 생성에서 주입받을수 있도록 한다.
public class MvcConfig implements WebMvcConfigurer {

    private final AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor);
    }
}

🦜 여기서 주의할점 여기서 생성자 주입할때 이때까지 난 @Autowierd를 사용했다.

이렇게 말이다.
하지만 순환참조가 일어날수 있기 때문에 @RequiredArgsConstructor 를 쓴다.
@RequiredArgsConstructor는 final로 선언된 객체를 생성해서 주입받을수 있도록 하는 어노테이션이다.!!!!! 꿀팁이다.!!!
🦜 그럼 호출한번해보자.

🦜 privateController로 호출하면 컨트롤러까지 못온다. AuthInterceptor에서 막아버리기 때문이다.

🦜 자이제 그럼 권한체크하는 예시를 짜보자. 🤔어떻게?할까?🤔

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        URI uri = UriComponentsBuilder.fromUriString(request.getRequestURI())
                .query(request.getQueryString())
                .build()
                .toUri();
        // 원래는 Session확인하거나 쿠키확인한다!!!!!

        String url = request.getRequestURI();
        log.info("request url : {}", url);

        boolean hasAnnotation = checkAnnotation(handler, Auth.class);
        log.info("has annotation : {}", hasAnnotation); // Auth어노테이션이 달려있나??? 확인하기.

        // 나의 서버는 모두  public 으로 동작을 하는데
        // 단! Auth 권한을 가진 요청에 대해서는 세션,쿠키 등등을 확인한다!!!!!

        if(hasAnnotation){
            //권한체크
            String query = uri.getQuery();
            if(query.equals("name=steve")){
                return true; // 이름이 스티브일때만 통과한다.
            }
        }
        return false;
    }

🤔🤔 그럼 내가 원하는 컨트롤러의 메서드만 인터셉터가 동작하게 못하나?

@Configuration
@RequiredArgsConstructor //fianl로 선언한 객체를 생성에서 주입받을수 있도록 한다.
public class MvcConfig implements WebMvcConfigurer {

    private final AuthInterceptor authInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor).addPathPatterns("/api/private/*");//내가 검사하고싶은 주소설정
        //excludePathPatterns()를 사용하여 특정 컨트롤러를 뺄수 있다.
    }
}

🦜 MvcConfig에 인터셉터 패턴을 입력하여 특정컨드롤러를 빼거나 설정 할 수 있다.!!

🦜 깔끔하게 예외처리까지 해주자

        if(hasAnnotation){
            //권한체크
            String query = uri.getQuery();
            if(query.equals("name=steve")){
                return true; // 이름이 스티브일때만 통과한다.
            }

            //권한이 없으면?? AuthException로 던져준다.
            throw new AuthException();
        }

AuthInterceptor의 권한체크가 실패하면
AuthExeption으로 던져주고

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(AuthException.class)
    public ResponseEntity authException(){
        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
    }

}

🦜 그걸 GlobalExceptionHandler가 처리해준다.

steve가 아니면 호출이 안된다!! 성공!!!

profile
OK가자

0개의 댓글