Intercepter
Controller 직전에 위치하여 특정 요청에 대해서 한번 걸러주는 역할로 Controller 전 후로 요청을 처리
Controller 실행 전 후로 Controller 입력 및 출력을 제어
Interface에 HandlerInterceptorAdapter 클래스를 상속받아서 사용
servlet-context.xml에 태그 추가하여 사용 가능(bean 등록을 하기 위해)
PreHandler의 경우 return을 통해 controller의 실행 여부 결정 가능
PostHandler의 경우 매개변수로 전달되는 ModelAndView를 통해 Controller에서 저장한 model 데이터를 컨트롤 가능
package com.spring.mvc.board.commons.interceptor;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
// interceptor class를 만들려면 HandlerInterceptor 인터페이스를 구현
public class BoardInterceptor implements HandlerInterceptor{
// preHandle은 컨트롤러로 들어가기 전 처리해야 할 로직을 작성
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("게시판 인터셉터 발동 확인 : preHandle");
// 해당 메소드는 override라서 매개변수를 바꾸거나 return 타입을 바꾸면 안됨
HttpSession session = request.getSession();
// HttpServletRequest 객체가 매개변수로 있으므로 getsession()으로 session가져올 수 있음
if (session.getAttribute("login") == null) {
System.out.println("회원 인증 실패 ");
response.setContentType("text/html; charset=UTF-8");
PrintWriter out = response.getWriter();
String htmlcode = "<script> \r\n"
+ "alert('로그인이 필요한 페이지입니다.'); \r\n"
+ "location.href='/'"
+ "</script>";
// 로그인을 하지 않으면 메인 페이지로 이동
out.print(htmlcode);
out.flush();
return false;
// return을 false로 주면 controller로 요청이 전달되지 않음
}
System.out.println("회원 인증 성공 ");
return true;
// return을 true로 리턴하면 아무일도 일어나지 않고 요청이 전달
}
// postHandle은 컨트롤러를 나갈 때 공통 처리해야 할 내용을 작성
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// ModelAndView가 있으므로 Controller에서 저장한 model의 값을 볼 수 있음
System.out.println("게시판 인터셉터 발동 확인 : postHandle");
System.out.println("모델 객체 내부 : " + modelAndView.getModel());
Object data = modelAndView.getModel().get("article");
System.out.println("article 이라는 이름의 데이터 : " + data);
System.out.println("뷰 페이지 이름 : " + modelAndView.getViewName());
// 컨트롤러에서 로직을 처리하고 나가는 흐름을 붙잡아서 모델 데이터가 제대로 전송되는지 확인하고
// 추가할 내용이나 수정할 내용이 있다면 모델 객체를 받아와서 추가, 수정 가능
// 기타 특징을 활용해서 흐름을 제어할 수 있음 (sendRedirect, viewName 수정을 통해)
}
}
자동 로그인은 Session과 Cookie를 활용하여 Auto Login 기능 수행 가능
autoLogin을 클릭하면 sessionid와 expired date를 db 컬럼으로 저장
사용자가 다시 접속했을 때 sessionid를 통해서 연산 진행 후 만약 같다면 자동 로그인 진행
비동기 방식으로 진행
// 로그인 요청 처리
@PostMapping("/loginCheck")
public String loginCheck(@RequestBody UserVO user, /* 1번 방법 HttpServletRequest request*/
HttpSession session, HttpServletResponse response) {
System.out.println("/user/loginCheck : POST");
// 서버에서 세션 객체를 얻는 방법
// 1. HttpServletRequest 객체 사용 (메서드의 매개변수로 넣어줌)
// HttpSession session = request.getSession();
// 2. 매개값으로 HttpSession 객체 받아서 사용 특정 메서드에 sesion정보 입력
// 오버라이딩을 할 경우 매개변수를 마음대로 바꾸지 못해서 2번은 문제가 발생할 수 있음
UserVO dbData = service.selectOne(user.getAccount());
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
// 암호화된 비밀번호를 가져오기 위해
if (dbData != null) {
if (encoder.matches(user.getPassword(), dbData.getPassword())) {
// 사용자가 입력한 비밀번호를 암호화 했을 때 기존에 저장된 암호화된 비밀번호가 같은지
// 로그인을 성공했다면 로그인 성공 대상으로 세션 정보 생성
session.setAttribute("login", dbData);
long limitTime = 60*60*24;
// 자동로그인 유효 기간
// 로그인을 성공했고 자동 로그인 체크 시 처리해야 할 내용
if (user.isAutoLogin()) {
// 자동 로그인을 체크했다면
// 자동 로그인 희망하는 경우 쿠키를 이용하여 자동 로그인 정볼르 저장
System.out.println("자동 로그인 쿠키 생성 중 ...");
// 세션 아이디를 가지고 와서 쿠키에 저장(고유한 값이 필요함)
// 쿠키 생성
Cookie loginCookie = new Cookie("loginCookie", session.getId());
// 이름이 loginCookie이고 값이 sessionID인 쿠키 생성
loginCookie.setPath("/");
// 쿠키가 동작할 수 있는 유효한 url 설정
loginCookie.setMaxAge((int) limitTime);
// 쿠키가 유효할 수 있는 기간
response.addCookie(loginCookie);
// 쿠키 추가
// 자동 로그인 유지 시간을 날짜 객체로 변환
// DB에 삽입하기 위해서 (밀리초)
long expiredDate = System.currentTimeMillis() + (limitTime * 1000);
Date limitDate = new Date(expiredDate);
// Date 객체의 생성자에 매개값으로 밀리초의 정수를 전달해주면 날짜 형태로 변경해줌
System.out.println("자동 로그인 만료 시간 : " + limitDate);
System.out.println("session id : " + session.getId());
service.keepLogin(session.getId(), limitDate, user.getAccount());
}
return "loginSuccess";
} else {
return "pwFail";
}
} else {
return "idFail";
}
}
로그아웃은 로그인으로 생성된 Session을 삭제하기만 하면 됨
자동 로그인 유저 로그아웃
자동 로그인을 유지하기 위해 생성한 Cookie는 request객체 안에 존재함으로 HttpServletRequest를 매개변수로 추가
생성한 Cookie를 삭제하고 로그인 유지를 하기 위해 DB에 저장한 값을 바꿔줌
// 로그아웃 처리
@GetMapping("/logout")
public ModelAndView logout(HttpServletRequest request, HttpServletResponse response, HttpSession session, RedirectAttributes ra
/*HttpServletResponse response*/) throws IOException {
System.out.println("/user/logout : GET");
// 자동 로그인 설정을 한 사용자는 쿠키를 삭제해야 완전히 로그아웃 됨
Cookie loginCookie = WebUtils.getCookie(request, "loginCookie");
// 쿠키는 request 객체 안에 존재함으로 매개변수로 request객체를 가져옴
// 쿠키의 이름이 loginCookie라는 쿠키를 쉽게 가져옴
String sessionId = "none";
// db에 저장된 session정보 바꿔야함
// 세션아이디, 만료시간
long changeExpiredDate = System.currentTimeMillis();
// 현재시간
Date chLimitDate = new Date(changeExpiredDate);
// 밀리초로 되어 있는 것을 날짜로 바꿔줌
UserVO user = (UserVO) session.getAttribute("login");
// user의 account가 필요함으로 session에서 정보를 받아옴
if (loginCookie != null) {
// 만약 사용자가 자동 로그인을 설정했을 때 쿠키가 존재한다면
loginCookie.setMaxAge(0);
// 쿠키의 수명을 0으로 바꿔 소멸
loginCookie.setPath("/");
// 쿠키 소멸 끝
response.addCookie(loginCookie);
service.keepLogin(sessionId, chLimitDate, user.getAccount());
}
session.invalidate();
// 세션 삭제
ra.addFlashAttribute("msg", "logout");
// 요청을 보낸 header.jsp에 msg 보냄
// return "redirect:/";
// 비동기 전송이라서 그냥 보내면 화면에 return한 데이터가 뜸
// response.sendRedirect("/");
// // sendRedirect로도 보낼 수 있음
// ModelAndView를 사용하게 되면 어디로 보낼 지 지정할 수 있음
ModelAndView mv = new ModelAndView();
mv.setViewName("redirect:/");
// 로그아웃 되었으니 홈화면으로 다시 요청해서 전달
return mv;
}