server.servlet.session.tracking-modes=cookie
쿠키(idCookie)
를 서버 응답 객체(HttpServletResponse)
에 addCookie
를 이용해 담아준다. 그럼 실제로 웹 브라우저에서는 Set-Cookie 프로퍼티
에 쿠키정보가 담겨져 반환 @PostMapping("/login")
public String login(@ModelAttribute LoginForm form, Model model,
RedirectAttributes redirectAttributes, HttpServletResponse response) {
Member loginMember = loginService.login(form.getLoginId(), form.getPassword());
if(loginMember == null) {
// 로그인 실패
model.addAttribute("msg", "로그인 실패");
return "login/loginForm";
}
// 로그인 성공
//쿠키에 시간 정보를 주지 않으면 세션 쿠키가 된다. (브라우저 종료시 모두 종료)
Cookie idCookie = new Cookie("memberId",String.valueOf(loginMember.getId()) );
response.addCookie(idCookie);
redirectAttributes.addFlashAttribute("msg","로그인성공");
return "redirect:/";
}
key
가 memberId
인 쿠키값을 찾아 memberId
변수에 할당해준다. required
가 false
이기에 쿠키정보가 없는 비회원도 접근 가능하다. private final MemberRepository memberRepository;
@GetMapping
public String homeV2(@CookieValue(name = "memberId", required = false)Long memberId,
Model model) {
// 로그인한 사용자가 아니라면 home으로 보낸다.
if(memberId == null) {
return "home";
}
// db조회
Member loginMember = memberRepository.findById(memberId);
// 사용자가 없으면 null 처리 필요
if(loginMember == null) {
return "home";
}
// loginHome : 로그인에 성공한 사람만이 볼 수 있는 화면
model.addAttribute("member",loginMember);
return "loginHome";
}
<h4 class="mb-3" th:text="|로그인 : ${member.name}|">로그인 사용자 이름</h4>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-secondary btn-lg" type="button"
th:onclick="|location.href='@{/items}'|">상품 관리</button>
</div>
<div class="col">
<form method="post" th:action="@{/logout}">
<button class="w-100 btn btn-dark btn-lg"
onclick="location.href='items.html'" type="submit">
로그아웃
</button>
</form>
</div>
</div>
@PostMapping("/logout")
public String logout(HttpServletResponse response) {
Cookie cookie = new Cookie("memberId", null);
// 쿠키 시간설정
cookie.setMaxAge(0);
response.addCookie(cookie);
return "redirect:/";
}
key/value
로 저장한 뒤 브라우저에서는 key값
만 가지고 있도록 하는 것이다. 이 개념을 그림으로 표현하면 다음과 같다. key
값을 한꺼번에 class
에 정의해 놓는 역할만 하는 class
HttpSession session = request.getSession(true);
를 하게되면
사용자 kim이 접속해도session_kim
(kim에 대한 세션) 이 생성되고,
사용자 jang이 접속해도session_jang
(jang에 대한 세션) 이 생성되어서
session.getAttribute(SessionConst.LOGIN_MEMBER);
을 하게 되면
사용자 kim은session_kim.getAttribute(SessionConst.LOGIN_MEMBER);
사용자 jangsession_jang.getAttribute(SessionConst.LOGIN_MEMBER);
을 수행하는거라서 충돌이 발생하지 않는다
- 사용자 kim이 로그인 요청
- 서버는 Session을 생성하고 생성한 SessionId를 쿠키에 담아서 클라이언트에게 전송
- 클라이언트 요청시 쿠키에 담긴 SessionId를 서버에 전송
- 서버는 Session 저장소에서 SessionId에 맞는 Session을 찾음
- 찾은 Session에서 해당 키값(SessionConst.LOGIN_MEMBER)에 맞는 객체(Member) 반환
public class SessionConst {
public static final String LOGIN_MEMBER = "loginMember";
}
request.getSession(true);
request.getSession(false);
인수를 전달하지 않을 경우 기본 값으로 true
이다.
session.invalidate();
@PostMapping("/login")
public String loginV2(@ModelAttribute LoginForm form, Model model,
RedirectAttributes redirectAttributes, HttpServletRequest request) {
Member loginMember = loginService.login(form.getLoginId(), form.getPassword());
if(loginMember == null) {
// 로그인 실패
model.addAttribute("msg", "로그인 실패");
return "login/loginForm";
}
// 로그인 성공
// session변수에 요청온거에서 getSession 획득
HttpSession session = request.getSession();
// 세션에 로그인 회원 정보 보관
session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
redirectAttributes.addFlashAttribute("msg","로그인성공");
return "redirect:/";
}
@PostMapping("/logout")
public String logoutV2(HttpServletRequest request) {
// 세션을 삭제
HttpSession session = request.getSession(false);
if(session != null) {
session.invalidate();
}
return "redirect:/";
}
@CookieValue
와 비슷하다. 클라이언트로부터 전달받은 내용의 세션중에서 key
가 일치하는게 있는지 찾는다. required
가 false
이니 만약 못찾으면 null
이 할당될 것이다// @GetMapping
public String homeV3(HttpServletRequest request ,Model model) {
HttpSession session = request.getSession(false);
// 로그인한 사용자가 아니라면 home으로 보낸다.
if(session == null) {
return "home";
}
Member loginMember = (Member)session.getAttribute(SessionConst.LOGIN_MEMBER);
// 사용자가 없으면 null 처리 필요
if(loginMember == null) {
return "home";
}
// loginHome : 로그인에 성공한 사람만이 볼 수 있는 화면
model.addAttribute("member",loginMember);
return "loginHome";
}
// session attribute 사용
@GetMapping
public String homeV4(
// session attribute를 뒤져서 member에 값을 넣어준다.
@SessionAttribute(name=SessionConst.LOGIN_MEMBER,required = false)Member loginMember
,Model model) {
// 사용자가 없으면 null 처리 필요
if(loginMember == null) {
return "home";
}
// loginHome : 로그인에 성공한 사람만이 볼 수 있는 화면
model.addAttribute("member",loginMember);
return "loginHome";
}
- 쿠키를 가지고 로그인 상태를 관리하는것은 코드도 복잡해지고 보안상 취약하다.
- 중요한 정보는 클라이언트에 노출시켜선 안되고 서버에서 관리해야 한다.
- 중요 정보는 서버에서 관리하며 정보에 접근할 추리불가능하고 중복이 되지않는 키를 이용해 서버와 클라이언트를 연결하도록 하며 이를 세션이라 한다.