compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
package com.example.filter.dto;
import lombok.*;
// lombok
//@Getter // getter method
//@Setter // setter method
@Data // getter, setter, toString ... 등의 메소드를 갖는 어노테이션
@NoArgsConstructor // 기본 생성자
@AllArgsConstructor // 전체 생성자
public class User {
private String name;
private int age;
}
package com.example.filter.controller;
import com.example.filter.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j // System.out.println();이 아닌 log를 남길 수 있게 도와준다
@RestController
@RequestMapping("/api")
public class ApiController {
@PostMapping("/user")
public User user(@RequestBody User user) {
log.info("User : {}", user);
return user;
}
}
package com.example.filter.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
@Slf4j
@Component
public class GlobalFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
// 전처리
String url = httpServletRequest.getRequestURI();
BufferedReader br = httpServletRequest.getReader();
br.lines().forEach(line -> {
log.info("url : {}, line : {}",url, line);
});
chain.doFilter(httpServletRequest, httpServletResponse);
// 후처리
}
}
package com.example.filter.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@Component
public class GlobalFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 우선 필터를 통해 HttpServletResponse, HttpServletRequest 클래스로 들어온 request와 response를 ContentCachingRequestWrapper와 ContentCachingResponseWrapper로 래핑해주어야 한다.
// HttpServletRequest 그대로 request.getReader 함수를 호출하거나 안에 있는 데이터를 읽으려고 하면, 단 한번만 읽을 수 있도록 톰캣에서 만들어두었기 때문에 이걸 다시 읽을 수 있는 클래스로 래핑해주어야 하기 때문이다.
ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);
// 생성 시에는 read를 하지 않고 길이만 초기화를 시켜준다
// 전처리
chain.doFilter(httpServletRequest, httpServletResponse);
// doFilter가 실행이 되면서 실내 내부 Spring 안으로 들어가서야
// writeToCache 메소드가 실행이 되서 request의 내용이
// content에 담겨 있게 되면서 읽을 수 있게 된다
// 그렇기에 log는 doFilter 이후에 처리해 준다
// 후처리
// req
String url = httpServletRequest.getRequestURI();
String reqContent = new String(httpServletRequest.getContentAsByteArray());
log.info("request url : {}, request body : {}", url, reqContent);
String resContent = new String(httpServletResponse.getContentAsByteArray());
int httpStatus = httpServletResponse.getStatus();
log.info("response status : {}, response body : {}", httpStatus, resContent);
}
}
package com.example.filter.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@Component
public class GlobalFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 우선 필터를 통해 HttpServletResponse, HttpServletRequest 클래스로 들어온 request와 response를 ContentCachingRequestWrapper와 ContentCachingResponseWrapper로 래핑해주어야 한다.
// HttpServletRequest 그대로 request.getReader 함수를 호출하거나 안에 있는 데이터를 읽으려고 하면, 단 한번만 읽을 수 있도록 톰캣에서 만들어두었기 때문에 이걸 다시 읽을 수 있는 클래스로 래핑해주어야 하기 때문이다.
ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);
// 생성 시에는 read를 하지 않고 길이만 초기화를 시켜준다
// 전처리
chain.doFilter(httpServletRequest, httpServletResponse);
// doFilter가 실행이 되면서 실내 내부 Spring 안으로 들어가서야
// writeToCache 메소드가 실행이 되서 request의 내용이
// content에 담겨 있게 되면서 읽을 수 있게 된다
// 그렇기에 log는 doFilter 이후에 처리해 준다
// 후처리
// req
String url = httpServletRequest.getRequestURI();
String reqContent = new String(httpServletRequest.getContentAsByteArray());
log.info("request url : {}, request body : {}", url, reqContent);
String resContent = new String(httpServletResponse.getContentAsByteArray());
int httpStatus = httpServletResponse.getStatus();
httpServletResponse.copyBodyToResponse();
log.info("response status : {}, response body : {}", httpStatus, resContent);
}
}
package com.example.filter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
@SpringBootApplication
@ServletComponentScan
public class FilterApplication {
public static void main(String[] args) {
SpringApplication.run(FilterApplication.class, args);
}
}
package com.example.filter.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Slf4j
@WebFilter(urlPatterns = "/api/user/*")
public class GlobalFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
ContentCachingRequestWrapper httpServletRequest = new ContentCachingRequestWrapper((HttpServletRequest) request);
ContentCachingResponseWrapper httpServletResponse = new ContentCachingResponseWrapper((HttpServletResponse) response);
// 전처리
chain.doFilter(httpServletRequest, httpServletResponse);
// 후처리
// req
String url = httpServletRequest.getRequestURI();
String reqContent = new String(httpServletRequest.getContentAsByteArray());
log.info("request url : {}, request body : {}", url, reqContent);
// res
String resContent = new String(httpServletResponse.getContentAsByteArray());
int httpStatus = httpServletResponse.getStatus();
httpServletResponse.copyBodyToResponse();
log.info("response status : {}, response body : {}", httpStatus, resContent);
}
}
package com.example.filter.controller;
import com.example.filter.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j // System.out.println();이 아닌 log를 남길 수 있게 도와준다
@RestController
@RequestMapping("/api/user")
public class ApiController {
@PostMapping("")
public User user(@RequestBody User user) {
log.info("User : {}", user);
return user;
}
}
package com.example.filter.controller;
import com.example.filter.dto.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Slf4j // System.out.println();이 아닌 log를 남길 수 있게 도와준다
@RestController
@RequestMapping("/api/temp")
public class ApiTempController {
@PostMapping("")
public User user(@RequestBody User user) {
log.info("Temp : {}", user);
return user;
}
}
package com.example.interceptor.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
// 모든 사용자가 사용 가능한 api
@RestController
@RequestMapping("/api/public")
public class PublicController {
@GetMapping("/hello")
public String hello() {
return "public hello";
}
}
package com.example.interceptor.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/private")
public class PrivateController {
@GetMapping("/hello")
public String hello() {
return "private hello";
}
}
package com.example.interceptor.annotation;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Auth {
}
package com.example.interceptor.interceptor;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@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 (Java script 파일이라던지 html 파일 등)
if(handler instanceof ResourceHttpRequestHandler) {
return true;
}
// annotation check
HandlerMethod handlerMethod = (HandlerMethod) handler;
if(null != handlerMethod.getMethodAnnotation(clazz) || null != handlerMethod.getBeanType().getAnnotation(clazz)) {
// Auth annotation이 있을 때는 true
return true;
}
return false;
}
}
package com.example.interceptor.config;
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;
// final로 선언된 객체들을 생성자에서 받을 수 있게 해준다, Spring에서는 @Autowired로도 받을 수 있지만 순환참조가 일어날 수 있다 그래서 최근에는 순환참조를 피하기 위해서 @RequiredArgsConstructor를 이용해서 생성자에서 받는경우가 많
@Configuration
@RequiredArgsConstructor
public class MvcConfig implements WebMvcConfigurer {
private final AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor);
}
}
package com.example.interceptor.controller;
import com.example.interceptor.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;
@Slf4j
@RestController
@RequestMapping("/api/private")
@Auth
public class PrivateController {
@GetMapping("/hello")
public String hello() {
log.info("private hello controller");
return "private hello";
}
}
package com.example.interceptor.interceptor;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@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 true;
}
private boolean checkAnnotation(Object handler, Class clazz) {
// resource (Java script 파일이라던지 html 파일 등)
if(handler instanceof ResourceHttpRequestHandler) {
return true;
}
// annotation check
HandlerMethod handlerMethod = (HandlerMethod) handler;
if(null != handlerMethod.getMethodAnnotation(clazz) || null != handlerMethod.getBeanType().getAnnotation(clazz)) {
// Auth annotation이 있을 때는 true
return true;
}
return false;
}
}
package com.example.interceptor.interceptor;
import com.example.interceptor.annotation.Auth;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@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);
boolean hasAnnotation = checkAnnotation(handler, Auth.class);
log.info("has annotation : {}",hasAnnotation);
return true;
}
private boolean checkAnnotation(Object handler, Class clazz) {
// resource (Java script 파일이라던지 html 파일 등)
if(handler instanceof ResourceHttpRequestHandler) {
return true;
}
// annotation check
HandlerMethod handlerMethod = (HandlerMethod) handler;
if(null != handlerMethod.getMethodAnnotation(clazz) || null != handlerMethod.getBeanType().getAnnotation(clazz)) {
// Auth annotation이 있을 때는 true
return true;
}
return false;
}
}
package com.example.interceptor.interceptor;
import com.example.interceptor.annotation.Auth;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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("request url : {}", url);
boolean hasAnnotation = checkAnnotation(handler, Auth.class);
log.info("has annotation : {}",hasAnnotation);
// 나의 서버는 모두 public으로 동작을 하는데
// 단! @Auth 권한을 가진 요청에 대해서는 세션, 쿠키, Param에서 검증
if(hasAnnotation) {
// 권한체크
String query = uri.getQuery();
log.info(query);
if(query.equals("name=steve")) {
return true;
}
return false;
}
return true;
}
private boolean checkAnnotation(Object handler, Class clazz) {
// resource (Java script 파일이라던지 html 파일 등)
if(handler instanceof ResourceHttpRequestHandler) {
return true;
}
// annotation check
HandlerMethod handlerMethod = (HandlerMethod) handler;
if(null != handlerMethod.getMethodAnnotation(clazz) || null != handlerMethod.getBeanType().getAnnotation(clazz)) {
// Auth annotation이 있을 때는 true
return true;
}
return false;
}
}
package com.example.interceptor.config;
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;
// final로 선언된 객체들을 생성자에서 받을 수 있게 해준다, Spring에서는 @Autowired로도 받을 수 있지만 순환참조가 일어날 수 있다 그래서 최근에는 순환참조를 피하기 위해서 @RequiredArgsConstructor를 이용해서 생성자에서 받는경우가 많
@Configuration
@RequiredArgsConstructor
public class MvcConfig implements WebMvcConfigurer {
private final AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor).addPathPatterns("/api/pirvate/*");
}
}
package com.example.interceptor.exception;
public class AuthException extends RuntimeException{
}
package com.example.interceptor.handler;
import com.example.interceptor.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();
}
}
package com.example.interceptor.interceptor;
import com.example.interceptor.annotation.Auth;
import com.example.interceptor.exception.AuthException;
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 javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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("request url : {}", url);
boolean hasAnnotation = checkAnnotation(handler, Auth.class);
log.info("has annotation : {}",hasAnnotation);
// 나의 서버는 모두 public으로 동작을 하는데
// 단! @Auth 권한을 가진 요청에 대해서는 세션, 쿠키, Param에서 검증
if(hasAnnotation) {
// 권한체크
String query = uri.getQuery();
log.info(query);
if(query.equals("name=steve")) {
return true;
}
throw new AuthException();
}
return true;
}
private boolean checkAnnotation(Object handler, Class clazz) {
// resource (Java script 파일이라던지 html 파일 등)
if(handler instanceof ResourceHttpRequestHandler) {
return true;
}
// annotation check
HandlerMethod handlerMethod = (HandlerMethod) handler;
if(null != handlerMethod.getMethodAnnotation(clazz) || null != handlerMethod.getBeanType().getAnnotation(clazz)) {
// Auth annotation이 있을 때는 true
return true;
}
return false;
}
}