Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

[로그인] Servlet Filter - 인증 체크 본문

인프런/[인프런] 스프링 MVC 2

[로그인] Servlet Filter - 인증 체크

Seung__ 2021. 9. 26. 22:40

로그인 하지 않은 사용자가 상세 페이지 또는 앞으로 추가될 페이지에 접근하는 것을 막고싶다.

 

 

1. LoginCheckFilter class 


  • whitelist : 필터를 적용하지 않을 url 지정. ->회원등록, 로그인, 로그아웃, css관련 url은 해당 로직과 관계 없음.
  • isLoginCheckPath() : 요청 url이 whitelist인지 아닌지 확인. PatternMatchinUtils를 사용하면 쉽게 비교 가능.
@Slf4j
public class LoginCheckFilter implements Filter {

    //얘네들은 필터 적용 안됨.
    private static final  String[] whitelist = {"/", "/member/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
                    //redirectURL 추가 : 로그인 페이지로 이동 후 로그인 성공시 현재 페이지로 redirect
                    httpResponse.sendRedirect("/login?redirectURL=" + requestURI);
                    return ; //servlet 호출, controller호출 안함.
                }
            }

            chain.doFilter(request, response);
        } catch (Exception e){
            throw e;//예외 로깅 가능하지만, 톰캣까지 예외를 보내줘야함.
        }finally {
            log.info("인증 체크 필터 종료 {}", requestURI);
        }
    }

    /**
     * whitelist의 경우 인증체크 안함.
     */
    private boolean isLoginCheckPath(String requestURI){
        return !PatternMatchUtils.simpleMatch(whitelist, requestURI);
    }
}
  • whitelist = {"/", "/members/add", "/login", "/logout","/css/*"};
    • 인증 필터를 적용해도 홈, 회원가입, 로그인 화면, css 같은 리소스에는 접근할 수 있어야 한다. 
    • 이렇게 화이트 리스트 경로는 인증과 무관하게 항상 허용.
    • 화이트 리스트를 제외한 나머지 모든 경로에는 인증 체크 로직을 적용
  • isLoginCheckPath(requestURI)
    • 화이트 리스트를 제외한 모든 경우에 인증 체크 로직을 적용한다.
  • httpResponse.sendRedirect("/login?redirectURL=" + requestURI);
    • 미인증 사용자는 로그인 하라고 로그인 화면으로 보내버린다. 
    • 이때 사용성 개선을 위해 현재 URL 정보를 QueryParamter로 같이 넘겨준다.
    • LoginController에서 해당 queryParam을 받아 현재(거절된 페이지)페이지로 redirect 시키면 된다.ㅏ
    • http://localhost:8080/login?redirectURL=/items
  • return;
    • 필터를 더는 진행하지 않는다.
    • 이후 필터는 물론 서블릿, 컨트롤러가 더는 호출되지 않는다. 
    • 앞서 redirect 를 사용했기 때문에 redirect 가 응답으로 적용되고 요청이 끝난다.

 

 

 

2. Filter 등록


  • 모든 요청에 대해 log남기는 filter다음으로 적용.
    @Bean
    public FilterRegistrationBean loginCheckFilter(){
        FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
        filterFilterRegistrationBean.setFilter(new LoginCheckFilter());
        filterFilterRegistrationBean.setOrder(2);
        filterFilterRegistrationBean.addUrlPatterns("/*"); //모든 url 적용

        return filterFilterRegistrationBean;
    }

 

 

 

3. LoginController


  • 미인증 사용자가 인증에 실패하여 로그인 화면으로 redirect되는 경우.
  • 거절된 페이지 url을 queryParam으로 같이 넘겨준다.
  • @RequestParam을 통해 해당 queryparam을 받는다.
  • 이 때 defaultValue를 "/"로 지정하여 queryParam이 없는 경우(최초 접근)는 home 으로 redirect!!
  • http://localhost:8080/login?redirectURL=/items
    @PostMapping("/login")
    public String loginV4(@Validated @ModelAttribute("loginForm") 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", "id 또는 pw가 맞지 않습니다.");
            return "login/loginForm";
        }

        //로그인 성공 처리
        //세션이 있으면 있는 세션 반환, 없으면 신규 세션 생성 후 반환.
        HttpSession session = request.getSession(true);
        //세션에 로그인 회원 정보를 보관
        session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);

        return "redirect:"+redirectURL;
    }

 

 

4. 정리 


  • 서블릿 필터를 잘 사용한 덕분에 로그인 하지 않은 사용자는 나머지 경로에 들어갈 수 없게 되었다. 
  • 공통 관심사를 서블릿 필터를 사용해서 해결한 덕분에 향후 로그인 관련 정책이 변경되어도 이 부분만 변경

 

 

5. GitHub : 210926 Certification check


 

GitHub - bsh6463/login

Contribute to bsh6463/login development by creating an account on GitHub.

github.com

 

Comments