로그인처리 - 3 (Filter)

나무·2023년 11월 20일

스프링 MVC

목록 보기
10/12
post-thumbnail

Filter 에 대해 간단히 알아 보았으니 이제 본격적으로 모든 페이지들에 대해 로그인 체크를 하는 필터를 개발해보자.

1. LoginCheckFilter : Filter 구현체

Filter 는 인터페이스였으므로 개발자가 사용 목적에 맞춰 구현을 해줘야한다.

LoginCheckFilter 라는 이름으로 Filter를 구현해주자.

package hello.login.web.filter;

import hello.login.web.SessionConst;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.PatternMatchUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@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);
    }
}

doFilter()

request 를 검사하여 로그인 사용자인지 비 로그인 사용자인지 필터링을 수행한다.

만일 비로그인 사용자일 경우 responsesendRedirect() 를 이용해 로그인 페이지로 리다이렉트 시켜버리고 종료된다.

로그인 사용자일 경우엔 chain.doFilter() 가 동작해 다음 filter로 이동한다.

whitelist

whitelist 에 담긴 URL 들은 로그인을 하지 않아도 들어갈 수 있는 목록들이다.

2. WebConfig : FilterRegistrationBean 등록

우리가 구현한 filter 객체를 스프링에서 사용하기 위해선 당연히 @Bean 으로 등록을 해줘야한다.

FilterRegistrationBean

@Configuration
public class WebConfig implements WebMvcConfigurer {

	...
    
    @Bean
    public FilterRegistrationBean loginCheckFilter() {
        FilterRegistrationBean<Filter> filterRegistrationBean = new FilterRegistrationBean<>();
        filterRegistrationBean.setFilter(new LoginCheckFilter());
        filterRegistrationBean.setOrder(2);
        filterRegistrationBean.addUrlPatterns("/*");

        return filterRegistrationBean;
    }
}

setFilter()

우리가 만들어준 필터를 세팅해준다.

setOrder()

필터도 여러가지를 등록할 수 있기 때문에 뭐가 먼저 수행될지 순서를 정해줘야한다. 이 경우에 우선순위는 2번째가 된다.

addUrlPatterns()

등록할 필터를 어떤 URL(페이지)에 적용할지 추가해준 메서드이다. 로그인의 경우 필터를 해야할 페이지가 압도적으로 많으므로 루트경로를 집어넣어준다.

대신 LoginFilterCheck 에서 whitelist를 이용해 로그인이 필요없는 URL 에 대해 예외처리를 해놓았으므로 괜찮다.

그냥 컴포넌트 스캔 쓰면 안돼?

@ComponentLoginCheckFilter 에 그냥 달아줘서 자동으로 컴포넌트스캔이 되도록 해도 되지만 FilterRegistrationBean 을 쓰는것이 스프링이 제공해주는 수많은 다양한 기능을 사용 할 수 있기 때문에 후자 방식을 선택했다.

3. LoginController

앞에서 필터를 구현할때 비로그인 사용자일경우 redirect 될 페이지 URL을 쿼리 파라미터로 넘겨주었다.

그렇기 때문에 GET /login 컨트롤러 메서드 또한 쿼리 파라미터를 전달 받을 수 있도록 수정해줘야한다.

@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;

    }

@RequestParam() 을 추가 해주었다.


본 포스트는
김영한의 스프링 MVC 2편 - 백엔드 웹 개발 활용 기술 강의 를 보고 정리했습니다.

profile
🍀 개발을 통해 지속 가능한 미래를 만드는데 기여하고 싶습니다 🍀

0개의 댓글