Spring-Interceptor

이호영·2022년 3월 6일
0

Spring

목록 보기
13/18

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

package com.example.intrerceptor.controller;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/public")
public class PublicController {

    @GetMapping("/hello")
    public String hello(){
        return "public hello";
    }
}
package com.example.intrerceptor.annotation;

import java.lang.annotation.*;

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

}
package com.example.intrerceptor.controller;

import com.example.intrerceptor.annotation.Auth;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Auth//세션검사
@RequestMapping("/api/private")
@Slf4j
public class PrivateController {

    @GetMapping("/hello")
    public String hello(){
        log.info("private hello controller");
        return "private hello";
    }
}
package com.example.intrerceptor.interceptor;

import com.example.intrerceptor.annotation.Auth;
import com.example.intrerceptor.exception.AuthException;
import com.sun.source.tree.BreakTree;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import org.springframework.web.util.UriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.URI;
import java.util.logging.Handler;
@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("request url : {}", url);
        boolean hasAnnotation= checkAnnotation(handler, Auth.class);
        log.info("has Anotation:{}" ,hasAnnotation);

        //내 서버는 모두 public으로 동작 하는데
        //단 Auth권한을 가진 요청에 대해서는 세션 쿠키 검사
        if(hasAnnotation){
            //권한 체크
            String query= uri.getQuery();

            if(query.equals("name=이호영")){
                return true;
            }

        }
        throw new AuthException();
    }

    private boolean checkAnnotation(Object handler, Class clazz){
        //리소스는 통과(자바 스크립트,HTML)
        if( handler instanceof ResourceHttpRequestHandler){
            return true;
        }

        //Annotation 체크
        HandlerMethod handlerMethod=(HandlerMethod) handler;

        if(null != handlerMethod.getMethodAnnotation(clazz)|| null != handlerMethod.getBeanType().getAnnotation(clazz)){
            return true; //Auth annotation이 있을경우
        }
        return false;
    }
}
package com.example.intrerceptor.handler;

import com.example.intrerceptor.exception.AuthException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(AuthException.class)
    public ResponseEntity authException(){

        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        //이호영이가 아닌 사용자는 401에러 발생
    }
}
package com.example.intrerceptor.config;

import com.example.intrerceptor.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/*"); //검사하고 싶은 패턴만 검사

    }
}
package com.example.intrerceptor.exception;

public class AuthException extends RuntimeException{
}

0개의 댓글