Java - Spring &&n SpringBoot

Spring - 서블릿 필터 다루기(2) : 로그인 여부 체크, 로그인 여부에 따른 페이지 접근

TerianP 2022. 8. 12.
728x90

서블릿 로그인 필터 만들기

  • 로그인을 했을 경우에만 특정한 페이지 접근을 허용하도록 하는 서블릿 필터
  • whiteList 배열은 로그인 없이 접근 가능한 페이지들를 모아놓은 배열이다.
  • doFilter 에서는 getRequestURI 를 통해서 서버로 요청된 uri 를 확인한다. 확인한 uri 에 대해서 isLoginCheckPath 메서드가 실행되는데 이 메서드를 통해서 해당 uri 가 whiteList - 접근 가능한 uri - 에 해당하는지 여부를 판단한다.
  • 만약 isLoginCheckPath 가 true 를 출력한다면 해당 uri 는 로그인해야만 접근 가능한 uri 로 판정되고 다시 session 을 통해 세션의 null 여부와 session 안에 담긴 값을 조사한다.
  • 즉 whiteList 배열에 속한 페이지가 아닌 경우는 filter 에 걸려서 session 검사를 받게 되고 세션이 없는 경우 로그인을 반드시 하도록 로그인 페이지로 보내게 된다.
    • 이때 redirectURL 파라미터와 현재 uri 를 붙이게 되면 로그인 후 맨 처음 요청했던 uri 로 이동하기 위해서이다.
// 로그인 여부에 따른 페이지 접근 필터
@Slf4j
public class LoginCheckFilter implements Filter {

    // whiteList 생성 => 로그인 상관없이 접근 가능한 페이지
    private static final String[]whiteList= {"/", "/home", "/members/newregisters", "/login", "/logout"};

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        String reqURI = req.getRequestURI();

        HttpServletResponse resp = (HttpServletResponse) response;

        try {
log.info("인증 체크 필터 시작 {}", reqURI);

            // 해당 uri 경로를 확인했을 때 만약 whiteList 에 해당하지 않는 경로라면
            // 아래의 로직을 실행
            if (isLoginCheckPath(reqURI)) {
log.info("인증 체크 로직 실행 {} ", reqURI);
                // 현재 session 을 통해 로그인한 사용자인지 확인
                HttpSession session = req.getSession(false);

                // 만약 세션이 null 이거나 session 안에 담긴 정보가 없다면,
                if (session == null || session.getAttribute(SessionConst.LOGIN_MEMBER) == null) {
log.info("미인증 사용자 요청 {} ", reqURI);

                    // 뒤에 redirectURL 을 찍어줌으로써 로그인 후 이전 페이지로 돌아올 수 있게 함
                    // 이전 페이지란 로그인하기 바로전에 간 페이지
                    resp.sendRedirect("/login?redirectURL=" + reqURI);
                    return;
                }
            }

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

    /*
     * 화이트 리스트의 경우 인증 체크 하지 않도록 하는 메서드
     * */
    private boolean isLoginCheckPath(String uri) {
        // spring 에서 제공하는 PatternMatchUtil 을 통해서 uri 가 해당 whiteList 안에 있는지 확인
        // 없다면 true, 있다면 false =>
        return !PatternMatchUtils.simpleMatch(whiteList, uri);
    }
}

 

SpringBean 설정

@Bean
public FilterRegistrationBean loginCheckFilterBean(){
    FilterRegistrationBean<Filter> filterBean = new FilterRegistrationBean<Filter>();
    filterBean.setFilter(new LoginCheckFilter());

    // 필터 순서 => 필터 체인 시 사용되는 순서
    // 이전 logFilter 가 살아있음으로 2번
    filterBean.setOrder(2);

    // 필수 적용 URL => 필터 적용 시 사용되는 url : /* 라면 모든 url 에 적용됨
    filterBean.addUrlPatterns("/*");

    return filterBean;
}

 

Controller 설정

  • Controller 에서 로그인 후 이동하는 경로를 파라미터로 받아온 redirectURL 의 값으로 설정해주면 로그인 후 그곳으로 redirect 된다.
@PostMapping("/login")
    public String loginWithHttpSession(@ModelAttribute LoginForm form,
                                       BindingResult bindingResult,
                                       HttpServletRequest request, HttpServletResponse res,
                                       @RequestParam(name = "redirectURL", defaultValue = "/") String redirectURL
    ) throws IOException {
        JSONObject jso = new JSONObject();
        // 에러 관리 메서드(아직 사용 X)
//        if (bindingResult.hasErrors()) {
//            return "members/login";
//        }

        // 1. loginForm 을 통해 로그인 정보들을 가져옴
        Member LoginMember = loginService.login(form.getLoginid(), form.getLoginpw());

        Map<String, Object> result = new HashMap<String, Object>();

        if (LoginMember == null) { // login 메서드에서 던져주는 값이 null 이면 로그인 실패
//            bindingResult.reject("login Fail", "아이디 또는 비밀번호가 맞지 않습니다");
            System.out.println("계정 정보 확인 불가. 로그인 실패");

            res.setContentType("text/html;charset=utf-8");
            // printWiter 객체는 java 단에서 javascript 를 사용할 수 잇게해주는 객체이다
            // memberController 에서의 내용도 마찬가지로 이를 사용한 것.
            PrintWriter out = res.getWriter();

            result.put("state", "fail");
            // out.println 으로 사용하자
            out.println("<script>alert('로그인 실패!! 계정 정보를 확인해주세요');</script>");
            out.flush(); // printwriter 종료

            return "members/login";

        } else if (form.getLoginid() == null || form.getLoginpw() == null) {
            System.out.println("아이디나 비밀번호 중 null 값 존재");

            res.setContentType("text/html;charset=utf-8");
            // printWiter 객체는 java 단에서 javascript 를 사용할 수 잇게해주는 객체이다
            // memberController 에서의 내용도 마찬가지로 이를 사용한 것.
            PrintWriter out = res.getWriter();

            result.put("state", "fail");
            // out.println 으로 사용하자
            out.println("<script>alert('아이디나 비밀번호가 비어있어요! 확인해주세요');</script>");
            out.flush(); // printwriter 종료

            return "members/login";
        }

        // 2. null 이외의 값 즉 member 객체라면 로그인 성공 처리
        // http 서블릿 세션을 활용하기 위해서는 httpservlerequest 가 필요함 : 세션이 있으면 세션 반환, 없으면 세션 생성
        // 이때 request.getSession() 에서 getSession() 의 파라미터안에는 true, false 두가지가 올 수 있음
        HttpSession session = request.getSession();

        // 세션에 회원 정보(LoginMember) 저장 후 홈으로 반환
        session.setAttribute(SessionConst.LOGIN_MEMBER, LoginMember);

        /** 이렇게 세션에 별도의 다른 값을 넣어 둘 수 있음 **/
        session.setAttribute("memberCode", LoginMember.getMEMBERCODE());

        log.info("redirectURL = {}", redirectURL);
        return "redirect:" + redirectURL;
    }

 

코드 확인

로그인 없이 member/memberList 에 접근한 모습

 

admin 으로 로그인 후 다시 회원리스트 - member/memberList 에 접근을 시도하였다 -

 

접근 가능한 것이 확인된다!

댓글