https://drcode-devblog.tistory.com/560
지난 포스팅에 이어서 이번에는 서블릿 HTTP 세션을 이용해서 로그인처리를 다뤄보겠다.
세션이라는 개념은 대부분의 웹 애플리케이션에 필요한 것이다.
어쩌면 웹이 등장하면서 부터 나온 문제이다.
서블릿은 세션을 위해 HttpSession 이라는 기능을 제공하는데, 지금까지 나온 문제들을 해결해준다.
위 포스팅에서 직접 구현한 세션의 개념이 이미 구현되어 있고, 더 잘 구현되어 있다
HttpSession 소개
서블릿이 제공하는 HttpSession 도 결국 우리가 직접 만든 SessionManager 와 같은 방식으로 동작한다.
서블릿을 통해 HttpSession 을 생성하면 다음과 같은 쿠키를 생성한다.
쿠키 이름이 JSESSIONID 이고, 값은 추정 불가능한 랜덤 값이다.
Cookie: JSESSIONID=5B78E23B513F50164D6FDD8C97B0AD05
HttpSession 사용
서블릿이 제공하는 HttpSession 을 사용하도록 개발해보자.
SessionConst
package hello.login.web;
public class SessionConst {
public static final String LOGIN_MEMBER = "loginMember";
}
HttpSession 에 데이터를 보관하고 조회할 때, 같은 이름이 중복 되어 사용되므로, 상수를 하나 정의했다.
LoginController - loginV3()
@PostMapping("/login")
public String loginV3(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletRequest request) {
if(bindingResult.hasErrors()) {
return "login/loginForm";
}
Member loginMember = loginService.login(form.getLoginId(), form.getPassword());
log.info("loginMember={}", loginMember);
if(loginMember == null) {
bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
return "login/loginForm";
}
// 로그인 성공 처리
// 세션이 있으면 세션 반환, 없으면 신규 세션을 생성
HttpSession session = request.getSession(); // default 파라미터 : true
// 세션에 로그인 회원 정보 보관
session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
return "redirect:/";
}
기존 loginV2() 의 @PostMapping("/login") 주석 처리
세션 생성과 조회
세션을 생성하려면 request.getSession(true) 를 사용하면 된다.
public HttpSession getSession(boolean create);
세션의 create 옵션에 대해 알아보면,
- request.getSession(true)
: 세션이 있으면 기존 세션을 반환한다.
: 세션이 없으면 새로운 세션을 생성해서 반환한다.
- request.getSession(false)
: 세션이 있으면 기존 세션을 반환한다.
: 세션이 없으면 새로운 세션을 생성하지 않는다. null 을 반환한다.
- request.getSession()
: 신규 세션을 생성하는 request.getSession(true) 와 동일하다.
세션에 로그인 회원 정보 보관
session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
세션에 데이터를 보관하는 방법은 request.setAttribute(..) 와 비슷하다.
하나의 세션에 여러 값을 저장할 수 있다.
LoginController - logoutV3()
@PostMapping("/logout")
public String logoutV3(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if(session != null) {
session.invalidate();
}
return "redirect:/";
}
기존 logoutV2() 의 @PostMapping("/logout") 주석 처리
session.invalidate() : 세션을 제거한다.
HomeController - homeLoginV3()
@GetMapping("/")
// 자동으로 타입컨버팅 해준다. 쿠키는 원래 String
public String homeLoginV3(HttpServletRequest request, Model model) {
HttpSession session = request.getSession(false);
if(session == null) {
return "home";
}
Member loginMember = (Member) session.getAttribute(SessionConst.LOGIN_MEMBER);
// 세션에 회원 데이터가 없으면 home
if (loginMember == null) {
return "home";
}
// 세션이 유지되면 로그인으로 이동
model.addAttribute("member", loginMember);
return "loginHome";
}
기존 homeLoginV2() 의 @GetMapping("/") 주석 처리
- request.getSession(false) : request.getSession() 를 사용하면 기본 값이 create: true 이므로,
로그인 하지 않을 사용자도 의미없는 세션이 만들어진다.
따라서 세션을 찾아서 사용하는 시점에는 create: false 옵션을 사용해서 세션을 생성하지 않아야 한다.
- session.getAttribute(SessionConst.LOGIN_MEMBER) : 로그인 시점에 세션에 보관한 회원 객체를 찾는다.
실행
JSESSIONID 쿠키가 적절하게 생성되는 것을 확인하자.
@SessionAttribute
스프링은 세션을 더 편리하게 사용할 수 있도록 @SessionAttribute 을 지원한다.
이미 로그인 된 사용자를 찾을 때는 다음과 같이 사용하면 된다. 참고로 이 기능은 세션을 생성하지 않는다. @SessionAttribute(name = "loginMember", required = false) Member loginMember
HomeController - homeLoginV3Spring()
@GetMapping("/")
// 자동으로 타입컨버팅 해준다. 쿠키는 원래 String
public String homeLoginV3Spring(
@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember, Model model) {
// 세션에 회원 데이터가 없으면 home
if (loginMember == null) {
return "home";
}
// 세션이 유지되면 로그인으로 이동
model.addAttribute("member", loginMember);
return "loginHome";
}
homeLoginV3() 의 @GetMapping("/") 주석 처리
세션을 찾고, 세션에 들어있는 데이터를 찾는 번거로운 과정을 스프링이 한번에 편리하게 처리해주는 것을 확인할 수 있다.
TrackingModes
로그인을 처음 시도하면 URL이 다음과 같이 jsessionid 를 포함하고 있는 것을 확인할 수 있다.
http://localhost:8080/;jsessionid=F59911518B921DF62D09F0DF8F83F872
이것은 웹 브라우저가 쿠키를 지원하지 않을 때 쿠키 대신 URL을 통해서 세션을 유지하는 방법이다.
이 방법을 사용하려면 URL에 이 값을 계속 포함해서 전달해야 한다.
타임리프 같은 템플릿은 엔진을 통해서 링크를 걸면 jsessionid 를 URL에 자동으로 포함해준다.
서버 입장에서 웹 브라우저가 쿠키를 지원하는지 하지 않는지 최초에는 판단하지 못하므로,
쿠키 값도 전달하고, URL에 jsessionid 도 함께 전달한다.
URL 전달 방식을 끄고 항상 쿠키를 통해서만 세션을 유지하고 싶으면 다음 옵션을 넣어주면 된다.
이렇게 하면 URL에 jsessionid 가 노출되지 않는다.
application.properties
server.servlet.session.tracking-modes=cookie
댓글