private final SessionManager sessionManager;를 선언 후 사용해보자.
//세션 관리자를 통해 세션을 생성하고, 회원 데이터 보관sessionManager.createSession(loginMember,response);
로그아웃에 적용
sessionManager.expire(request);
홈에 적용
@GetMapping("/")publicStringhomeLoginV2(HttpServletRequestrequest,Modelmodel){//세션 관리자에 저장된 회원 정보 조회Membermember=(Member)sessionManager.getSession(request);if(member==null){return"home";}//로그인model.addAttribute("member",member);return"loginHome";}
세션이 쿠키와 다른 특별한 기술은 아니다.
사실 세션이라는 것이 뭔가 특별한것이 아니라 단지 쿠키를 사용하는데, 서버에서 데이터를 유지하는 방법일 뿐이다.
그런데 프로젝트마다 이러한 세션 개념을 직접 개발하는 것은 상당히 불편할 것이다. 그래서 서블릿도 세션 개념을 지원한다.
이제 직접 만드는 세션 말고, 서블릿이 공식 지원하는 세션을 알아보자.
서블릿이 공식 지원하는 세션은 우리가 직접 만든 세션과 동작 방식이 거의 같다.
추가로 세션을 일정시간 사용하지 않으면 해당 세션을 삭제하는 기능을 제공한다.
로그인 처리하기 - 서블릿 HTTP 세션1
세션이라는 개념은 대부분의 웹 애플리케이션에 필요한 것이다.
서블릿은 세션을 위해 HttpSession이라는 기능을 제공하는데, 지금까지 나온 문제들을 해결해준다.
HttpSession 소개
서블릿이 제공하는 HttpSession도 결국 우리가 직접 만든 SessionManager와 같은 방식으로 동작한다.
따라서 세션을 찾아서 사용하는 시점에는 create: false 옵션을 사용해서 세션을 생성하지 않아야 한다.
session.getAttribute("loginMember")
@GetMapping("/")publicStringhomeLoginV3(HttpServletRequestrequest,Modelmodel){//세션이 없으면 homeHttpSessionsession=request.getSession(false);if(session==null){return"home";}MemberloginMember=(Member)session.getAttribute("loginMember");//세션에 회원 데이터가 없으면 homeif(loginMember==null){return"home";}//세션이 유지되면 로그인으로 이동model.addAttribute("member",loginMember);return"loginHome";}
세션 생성과 값 설정
세션을 생성하려면 request.getSession(true)를 사용하면 된다.
create 옵션은 true와 false를 가질 수 있는데 그 종류에 따라 기능이 다르다.
true
세션이 있으면 기존 세션을 반환한다.
세션이 없으면 새로운 세션을 생성해서 반환한다.
false
세션이 있으면 기존 세션을 반환한다.
세션이 없으면 새로운 세션을 생성하지 않고 null을 반환한다.
true나 false를 지정하지 않으면 기본값인 true를 사용한다.
세션에 값을 설정하고 싶다면 session.setAttribute(키, 값);를 사용하면 된다.
세션에 설정한 값을 가져오고 싶다면 session.getAttribute(키);를 사용하면 된다.
로그인 처리하기 - 서블릿 HTTP 세션2
스프링은 세션을 더 편리하게 사용할 수 있도록 @SessionAttribute을 지원한다.
이미 로그인한 사용자 정보 찾기
컨트롤러에서 @SessionAttribute(name = "loginMember", required = false) Member loginMember를 사용하면 된다.
참고로 이 기능은 세션을 생성하지 않는다.
@GetMapping("/")publicStringhomeLoginV3Spring(@SessionAttribute(name="loginMember",required=false)MemberloginMember,Modelmodel){//세션에 회원 데이터가 없으면 homeif(loginMember==null){return"home";}//세션이 유지되면 로그인으로 이동model.addAttribute("member",loginMember);return"loginHome";}
세션 정보와 타임아웃 설정
세션이 갖고 있는 정보
sessionId
세션 ID
JSESSIONID의 값이다.
예시 : 34B14F008AA3527C9F8ED620EFD7A4E1
maxInactiveInterval
세션의 유효 시간
보통 30분을 많이 쓴다.
초 단위로 설정되어 있다.
creationTime
세션 생성일시
lastAccessedTime
세션과 연결된 사용자가 최근에 서버에 접근한 시간
클라이언트에서 서버로 sessionId(JSESSIONID)를 요청한 경우에 갱신된다.
isNew
새로 생성된 세션인지에 대한 여부
세션 타임아웃
사용자들이 직접 로그아웃하는 경우라면 세션을 삭제시키면 되겠지만, 그냥 웹 브라우저를 종료시켜버리면 어떻게 해야할까?
HTTP는 비연결성이기 때문에 서버 입장에서는 해당 사용자가 웹 브라우저를 종료한 것인지 아닌지 알 수 없다.
따라서 서버에서 세션 데이터를 언제 삭제해야 하는지 판단하기가 어렵다.
그렇다고 남아있는 세션을 무한정 보관하면 다음과 같은 문제가 발생할 수도 있다.
세션과 관련된 쿠키(JSESSIONID)를 탈취 당했을 경우 오랜 시간이 지나도 해당 쿠키로 악의적인 요청을 할 수 있다.
세션은 기본적으로 메모리에 생성된다.
메모리의 크기가 무한하지 않기 때문에 꼭 필요한 경우만 생성해서 사용해야 한다.
10만명의 사용자가 로그인하면 10만개의 세션이 생성되는 것이다.
그래서 세션의 종료 시점이라는 것이 존재한다.
로그인 시점으로 잡으면 도중에 다시 로그인해야 하는 번거로움이 있다.
보통은 HttpSession을 통해 최근 요청한 시간 기준으로 종료 시점을 잡는다.
server.servlet.session.timeout=1800 속성을 통해 세션 유지 시간을 지정할 수 있다.
application.properties에서 설정한다.
명시하지 않으면 기본 30분으로 잡힌다.
해당 값은 초 단위로 지정한다.
특정 세션 단위로 시간을 지정하려면 session.setMaxInactiveInterval(1800);처럼 지정하면 된다.
세션의 lastAccessedTime 이후로 timeout 시간이 지나면 WAS가 내부에서 해당 세션을 제거한다.
세션 시간 변경 시 주의점
세션에는 최소한의 데이터만 보관해야 한다.
보관한 데이터 용량 * 사용자 수로 세션의 메모리 사용량이 급격하게 늘어나서 장애로 이어질 수 있다.
세션의 시간을 너무 길게 가져가면 메모리 사용이 계속 누적 될 수 있다.
세션 시간을 변경하고 싶으면 기본이 30분이라는 것을 기준으로 고민해보자.
TrackingModes
로그인을 처음 시도하면 URL이 다음과 같이 jsessionid 를 포함하고 있는 것을 확인할 수 있다.