서블릿 필터
- 필터는 웹과 관련된 공통 관심사(로그인, 사용자 권한 등)를 처리할 때 주로 사용
- 지정한 URL 패턴에 대해 거름막 역할을 해주는 기능
필터 흐름
- HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러
필터 제한
- HTTP 요청 -> WAS -> 필터 -> 서블릿 -> 컨트롤러 // 로그인 사용자
- HTTP 요청 -> WAS -> 필터(적절하지 않은 요청이라 판단 시 서블릿 호출 X) // 비 로그인 사용자
필터 체인
- HTTP 요청 -> WAS -> 필터1 -> 필터2 -> 필터3 -> 서블릿 -> 컨트롤러
- 필터는 체인으로 구성
- 중간에 필터를 자유롭게 추가 가능(순서 지정 가능)
Filter 인터페이스
public interface Filter {
public default void init(FilterConfig filterConfig) throws ServletException
{}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException;
public default void destroy() {}
}
- 필터 인터페이스를 구현하고 등록하면 서블릿 컨테이너가 필터를 싱글톤 객체로 생성, 관리
- init() : 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출
- doFilter() : 고객의 요청이 올 때 마다 해당 메서드가 호출됨. 해당 메서드에 필터 로직 구현
- destroy() : 필터 종료 메서드, 서블릿 컨테이너가 종료될 때 호출
서블릿 필터를 사용하여 요청 로그 남기기
1. 필터 구현
@Slf4j
public class LogFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("log filter init");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("log filter doFilter");
HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestURI = httpRequest.getRequestURI();
String uuid = UUID.randomUUID().toString();
try{
log.info("REQUEST [{}][{}]", uuid, requestURI);
chain.doFilter(request, response); // 다음 필터 호출
} catch(Exception e){
throw e;
} finally{
log.info("RESPONSE [{}][{}]", uuid, requestURI);
}
}
@Override
public void destroy() {
log.info("log filter destroy");
Filter.super.destroy();
}
}
2. 필터 적용
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean logFilter(){
FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
filterFilterRegistrationBean.setFilter(new LogFilter()); // 적용 할 필터 넣기
filterFilterRegistrationBean.setOrder(1); // 순서
filterFilterRegistrationBean.addUrlPatterns("/*"); // 필터 넣을 url 패턴
return filterFilterRegistrationBean;
}
}
3. 실행
서블릿 필터를 이용하여 인증 체크
1. 필터 구현
@Slf4j
public class LoginCheckFilter implements Filter {
private static final String[] whitelist = {"/","/members/add","/login", "/logout", "/css/*"};
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String requestURI = httpRequest.getRequestURI();
HttpServletResponse httpResponse = (HttpServletResponse) response;
try{
log.info("인증 체크 필터 시작 {}", requestURI);
if(isLoginCheckPath(requestURI)){
log.info("인증 체크 로직 실행 {}", requestURI);
HttpSession session = httpRequest.getSession(false);
if(session == null || session.getAttribute(SessionConst.LOGIN_MEMBER) == null){
log.info("미인증 사용자 요청 {}", requestURI);
//로그인으로 redirect
httpResponse.sendRedirect("/login?redirectURL=" + requestURI);
return; // 컨트롤러 호출하지 않고 return
}
}
chain.doFilter(request, response);
} catch(Exception e){
throw e;
} finally {
log.info("인증 체크 필터 종료 {}", requestURI);
}
}
/**
* 화이트 리스트의 경우 인증 체크 x
*/
private boolean isLoginCheckPath(String requestURI){
return !PatternMatchUtils.simpleMatch(whitelist,requestURI);
}
}
2. 필터 적용
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean logFilter(){
FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
filterFilterRegistrationBean.setFilter(new LogFilter()); // 적용 할 필터 넣기
filterFilterRegistrationBean.setOrder(1); // 순서
filterFilterRegistrationBean.addUrlPatterns("/*"); // 필터 넣을 url 패턴
return filterFilterRegistrationBean;
}
@Bean
public FilterRegistrationBean loginCheckFilter(){
FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
filterFilterRegistrationBean.setFilter(new LoginCheckFilter()); // 적용 할 필터 넣기
filterFilterRegistrationBean.setOrder(2); // 순서
filterFilterRegistrationBean.addUrlPatterns("/*"); // 필터 넣을 url 패턴
return filterFilterRegistrationBean;
}
}
3. 실행
필터를 이용한 redirect
httpRequest.getRequestURI()를 통해 사용자가 요청한 url을 저장하여 필터 통과 시 redirect
@PostMapping("/login")
public String loginV4(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult,
@RequestParam(defaultValue = "/") String redirectURL,
HttpServletRequest request){
if(bindingResult.hasErrors()){
return "login/loginForm";
}
Member loginMember = loginService.login(form.getLoginId(), form.getPassword());
if(loginMember == null){
bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
return "login/loginForm";
}
// 로그인 성공 처리
// 세션이 있으면 있는 세션 반환, 없으면 신규 세션을 생성
HttpSession session = request.getSession();
// 세션에 로그인 회원 정보 보관
session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
return "redirect:" + redirectURL; // 인증 전 url로 redirect
}
'Spring > MVC' 카테고리의 다른 글
서블릿 예외 처리 (0) | 2024.07.20 |
---|---|
스프링 인터셉터 (0) | 2024.07.11 |
Bean Validation (0) | 2024.06.29 |
Validator (0) | 2024.06.28 |
BindingResult (0) | 2024.06.27 |