로그인 처리2 - 필터, 인터셉터

김성지·2022년 5월 30일

스프링기초

목록 보기
11/13

서블릿 필터

필터를 적용하게 되면 필터가 호출 된 다음에 서블릿이 호출된다.

필터는 체인으로 구성되는데, 중간에 필터를 자유롭게 추가 가능함.

필터 인터페이스를 구현하고 등록하면 서블릿 컨테이너가 필터를 싱글톤 객체로 생성하고, 관리한다.

  • init(): 필터 초기화 메서드, 서블릿 컨테이너가 생성될 때 호출된다.
  • doFilter():고객의 요청이 올 때 마다 해당 메서드가 호출된다. 필터의 로직을 구현하면 된다.
  • destroy(): 필터 종료 메소드, 서블릿 컨테이너가 종료될 때 호출된다.
@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 {
 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");
 }
}
  1. HTTP 요청이 아닌 겨웅까지 고려해서 만든 인터페이스 이므로 다운캐스팅 해주기
    2.chain.doFilter(request,response)
    다음 필터가 있으면 필터를 호출하고, 필터가 없으면 서블릿을 호출한다.
    이 로직을 호출하지 않으면 다음 단계로 진행되지 않음!
@Configuration
public class WebConfig {
 @Bean
 public FilterRegistrationBean logFilter() {
 FilterRegistrationBean<Filter> filterRegistrationBean = new
FilterRegistrationBean<>();
 filterRegistrationBean.setFilter(new LogFilter());
 filterRegistrationBean.setOrder(1);
 filterRegistrationBean.addUrlPatterns("/*");
 return filterRegistrationBean;
 }
}

@Configuration 에 필터 등록하자

인증 체크 필터

@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; //여기가 중요, 미인증 사용자는 다음으로 진행하지 않고 끝!
 }
 }
 chain.doFilter(request, response);
 } catch (Exception e) {
 throw e; //예외 로깅 가능 하지만, 톰캣까지 예외를 보내주어야 함
 } finally {
 log.info("인증 체크 필터 종료 {}", requestURI);
 }
 }
 /**
 * 화이트 리스트의 경우 인증 체크X
 */
 private boolean isLoginCheckPath(String requestURI) {
 return !PatternMatchUtils.simpleMatch(whitelist, requestURI);
 }
}
  • whitelist --> 인증 필터를 적용해도 홈,회원가입, 로그인화면, css 같은 리소스에는 접근할 수 있어야함.
  • isLoginCheckPath -> 화이트 리스트를 제외한 모든 경우에 인증 체크 로직을 적용한다.
  • httpResponse.sendRedirect("/login?redirectURL=" + requestURI)
    -->
    미인증 사용자는 로그인 화면으로 리다이렉트 한다.
    물론 /login 컨트롤러에서 로그인 성공시 해당 경로로 이동하는 기능은 추가로 개발해야 함
@Bean
public FilterRegistrationBean loginCheckFilter() {
 FilterRegistrationBean<Filter> filterRegistrationBean = new
FilterRegistrationBean<>();
 filterRegistrationBean.setFilter(new LoginCheckFilter());
 filterRegistrationBean.setOrder(2);
 filterRegistrationBean.addUrlPatterns("/*");
 return filterRegistrationBean;
}

필터 추가하기

@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());
 log.info("login? {}", loginMember);
 if (loginMember == null) {
 bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
 return "login/loginForm";
 }
 //로그인 성공 처리
 //세션이 있으면 있는 세션 반환, 없으면 신규 세션 생성
 HttpSession session = request.getSession();
 //세션에 로그인 회원 정보 보관
 session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
 //redirectURL 적용
 return "redirect:" + redirectURL;
}

redirect 처리방식

스프링 인터셉터

사용하려면 HandlerInterceptor 인터페이스를 구현하면 댐

함수들이 default 로 선언되어있음

@Configuration
public class WebConfig implements WebMvcConfigurer {
 @Override
 public void addInterceptors(InterceptorRegistry registry) {
 registry.addInterceptor(new LogInterceptor())
 .order(1)
 .addPathPatterns("/**")
 .excludePathPatterns("/css/**", "/*.ico", "/error");
 }
 //...
}

인터셉터 등록은 이렇게 한다
webMvcConfigurer가 제공하는 addInterceptors()를 사용해서 인터셉터 등록하기

세밀한 url등록 가능한데 이건 더 찾아봐서 필요할 때 써야 할 듯

@Slf4j
public class LoginCheckInterceptor implements HandlerInterceptor {
 @Override
 public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
 String requestURI = request.getRequestURI();
 log.info("인증 체크 인터셉터 실행 {}", requestURI);
 HttpSession session = request.getSession(false);
 if (session == null || session.getAttribute(SessionConst.LOGIN_MEMBER)
== null) {
 log.info("미인증 사용자 요청");
 //로그인으로 redirect
 response.sendRedirect("/login?redirectURL=" + requestURI);
 return false;
 }
 return true;
 }
}

인터셉터방식의 등록

0개의 댓글