😎🤔🦜
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";
}
}
@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가 아니면 호출이 안된다!! 성공!!!