μΉ μ΄ν리μΌμ΄μ μμ μ¬μ©μμ μ¬μ©μ±μ μ¦μ§μν€κΈ° μν΄μλ μμ²ν μ¬μ©μ μ 보λ₯Ό μλ²μμ κ΄λ¦¬νλ κ³Όμ μ΄ νμν μλ μλ€. κ·Έλ°λ° HTTP νλ‘ν μ½μ statelessν μ±μ§μ κ°μ§κ³ μκΈ° λλ¬Έμ μμ²μμ μνλ₯Ό μ μ§μν€μ§ μλλ€. κ·Έλ λ€λ©΄ μ΄λ»κ² μμ²μμ μ 보λ₯Ό μ μ§μν¬ μ μμκΉ?
μΏ ν€λ§ μ¬μ©νμ¬ μ μ μ μ 보λ₯Ό μ μ§νλ λ°©λ²
μλ²μ ν΄λΌμ΄μΈνΈμ λν
ν΄λΌμ΄μΈνΈ : λ‘κ·ΈμΈ ν λ
μλ² : OK, Cookie μ μ₯μμ Member ν€κ° μ μ₯ν΄. λ€μλΆν° μμ²ν λ ν¬ν¨ν΄μ μ μ‘ν΄μ€.
ν΄λΌμ΄μΈνΈ : GET, Cookie ν¬ν¨, μ 보 보μ¬μ€
μλ² : OK, μ μ μ 보 νμΈ, μ 보 보μ¬μ€κ².
ν΄λΌμ΄μΈνΈ : λΈλΌμ°μ μ’ λ£, λ§λ£ λ μ§κ° μλ€? μΈμ μΏ ν€λκΉ μμ
or λ§λ£ λ μ§κ° μλ€ μμ μν΄! λ§λ£ λ μ§μΌ λ μμ
μΏ ν€ κ΅¬ννκΈ° Response.setCookie()
첫 λ‘κ·ΈμΈ μ±κ³΅
Cookie cookie = new Cookie("memberId", String.valueOf(getId()));
response.setCookie(cookie);
return "redirect:/";
λ‘κ·ΈμΈ λ‘μ§
public String login(@CookieValue(name = "memberId"), required = false) Long memberId, Model model) {
if (memberId == null) {
// μΏ ν€κ° μμΌλ―λ‘ λ‘κ·ΈμΈ μ°½μΌλ‘ μ΄λ
}
// μΏ ν€ νμΈ, μΏ ν€ κ°μΌλ‘ μ¬μ©μ μ 보 κ°μ Έμ€κΈ°
Member member = memberRepository.findById(memberId);
model.addAtribute("member", member);
}
λ‘κ·Έμμ λ‘μ§
cookie.setMaxAge(0);
response.setCookie(cookie);β
μΏ ν€μ μ¬κ°ν 보μλ¬Έμ
μΏ ν€μλ κ΅μ₯ν μ¬κ°ν 보μλ¬Έμ κ° μ‘΄μ¬νλ€. 첫λ²μ§Έλ‘ μλ²μ μ μ‘νλ μΏ ν€λ₯Ό μ‘°μνμ¬ μλ²μ μ³μ§ μμ μμ²μ μλν μλ μλ€. λλ²μ§Έλ‘ μΏ ν€κ° λΈλΌμ°μ μ μ μ₯λκΈ° λλ¬Έμ μμ²μ PCκ° νΈλ¦΄ κ²½μ° μΏ ν€κ° νμ³μ§ νλ₯ μ΄ κ΅μ₯ν λμΌλ©° λΈλΌμ°μ μμ μλ²λ‘ μΏ ν€ μ 보λ₯Ό μ μ‘νλ κ³Όμ μ νμ³μ§ νλ₯ μ΄ λλ€. λν μ΄λ₯Ό ν΅ν΄ μΏ ν€λ₯Ό νμ·¨ νλ©΄ ν΄μ»€λ μλ²λ₯Ό ν΅ν΄ μ
μμ μΈ μμ²μ κ³μ μλνμ¬ μ°μμ μΈ νΌν΄λ₯Ό μ
νκ² λλ€.
μμ λ¬Έμ λ€μ μμ½κ² ν΄κ²°νκΈ° μν΄ λ³΄ν΅μ μΏ ν€μ μΈμ
μ κ°μ΄ μ¬μ©νλ€. νλ² μμΈν μμ보λλ‘ νμ.
μ°Έκ³ ) ν ν°μ΄λ 무μμΌκΉ? μΈμ
κ³Ό μ°¨μ΄μ μ 무μμ΄μ§?
ν΄λΌμ΄μΈνΈ : SessionIDλ ν ν°μ ν¬ν¨νμ¬ μμ²μ μ μ‘νλ€λ μ μμλ μ μ¬νλ€.
μλ² : μΈμ μ νμ©νλ κ²½μ°μλ μλ²κ° μΈμ μ μ₯μλ₯Ό λ³λλ‘ μ΄μνκ³ , ν ν°μ νμ©νλ κ²½μ°μλ μλ²λ λ¨μν ν ν°μ μνΈν, 볡νΈννλ μ± μλ§μ κ°μ§κ³ μλ€λ κ²μμ μ°¨μ΄κ° μ‘΄μ¬νλ€.
μΏ ν€μ μΈμ μ ν΅ν΄ μ μ μ μ 보λ₯Ό μ μ§νλ λ°©λ²
μΏ ν€μ 보μλ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄μλ κ²°κ΅ λ§€νλ μμμ κ°μ μ μ μκ² μ ν΄μ£Όκ³ μ€μν μ 보λ€μ λͺ¨λ μλ²μμ κ΄λ¦¬ν΄μΌ νλ€λ κ²μ μ μ μλ€. μ΄λ κ² μλ²μ μ€μν μ 보λ₯Ό 보κ΄νκ³ μ°κ²°μ μ μ§νλ κ²μ μΈμ μ΄λΌκ³ νλ€.
μλ²μ ν΄λΌμ΄μΈνΈμ λν
ν΄λΌμ΄μΈνΈ : λ‘κ·ΈμΈ ν λ
μλ² : OK μ λ³΄κ° λ§λ€, λ΄ μΈμ μ μ₯μμ λ μ 보λ₯Ό μ μ₯ ν΄λμΌκ² λ€. λλ λμκ² μ 보λ₯Ό μ°Ύμ μ μλ KeyμΈ sessionIDλ₯Ό μ€κ² μΏ ν€ μ μ₯μμ μ μ₯ν΄.
ν΄λΌμ΄μΈνΈ : GET, Cookie ν¬ν¨, μ 보 보μ¬μ€
μλ² : OK, sessionIdμ 맀νλ μ λ³΄κ° μ‘΄μ¬νλ€, μ 보 보μ¬μ€κ²
μμ κ°μ΄ μΈμ
μ μ¬μ©ν¨μΌλ‘μ ν΄κ²°λλ λ¬Έμ λ λ€μκ³Ό κ°λ€.
1. sessionIDλ₯Ό ν΄μ»€κ° μμ λΆκ°λ₯ν κ°μΌλ‘ μμλ‘ μμ±νλ€.
2. μ€μν μ 보λ₯Ό μλ²μλ§ μ μ₯νμ¬ Local PCμμ νμ·¨λ μ°λ €κ° μλ€.
3. μΈμ
λ§λ£ μκ°μ 짧κ²νμ¬ sessionIDλ₯Ό νΈμ΄κ°λ μ
μμ μΈ νλμ μ·¨ν μ μλλ‘ νλ€.
μΈμ ꡬννκΈ°
κΉμ μ΄ν΄λ₯Ό μν΄ μ§μ μΈμ μ ꡬνν΄λ³΄μ. μ’ λ μ¬μ΄ μ΄ν΄λ₯Ό μν΄ μλ²μ ν΄λΌμ΄μΈνΈμ λνμ λ‘μ§μ λ§€μΉ μμΌλ΄€λ€.
ν΄λΌμ΄μΈνΈ : λ‘κ·ΈμΈ ν λ
μλ² : λ΄ μΈμ μ μ₯μμ λ μ 보λ₯Ό μ μ₯ ν΄λμΌκ² λ€. λλ λμκ² μ 보λ₯Ό μ°Ύμ μ μλ KeyμΈ sessionIdλ₯Ό μ€κ² μΏ ν€ μ μ₯μμ μ μ₯ν΄
public void createSession(Object value, HttpServletResponse response) {
// sessionID μμ±
String sessionId = UUID.randomUUID().toString();
// μΈμ
μ μ₯μμ sessionIdμ value μ μ₯
sessionStore.put(sessionId, value);
// sessionIdλ‘ μλ΅ μΏ ν€λ₯Ό μμ±ν΄μ ν΄λΌμ΄μΈνΈμ μ λ¬
Cookie cookie = new Cookie(SESSION_COOKIE_NAME, sessionId);
response.addCookie(cookie);
}
UUID.randomUUID()λ₯Ό νμ©νκ² λλ©΄ μ½κ² UUID λλ€ν€λ₯Ό μ»μ μ μλ€. μ»μ΄λΈ `sessionId`λ₯Ό keyλ‘ νμ¬ `Map`μ μ μ μ 보λ₯Ό μ μ₯νλ€. κ³Όμ μ λ§μΉ ν `response`μ `sessionId`λ₯Ό ν¬ν¨μμΌ μλ΅νλ€.
ν΄λΌμ΄μΈνΈ : Get, Cookie ν¬ν¨, μ 보 보μ¬μ€
μλ² : OK, sessionIdμ 맀νλ μ λ³΄κ° μ‘΄μ¬νλ€, μ 보 보μ¬μ€κ²
public Object getSession(HttpServletRequest request) {
// μΈμ
κ³Ό κ΄λ ¨λ μΏ ν€ κ°μ Έμ€κΈ°
Cookie cookie = findCookie(request, SESSION_COOKIE_NAME);
if (cookie == null) return null;
// μΏ ν€μ μ μ₯λ sessionIdλ₯Ό ν΅ν΄ μΈμ
μ κ°μ Έμ¨λ€
return sessionStore.get(cookie.getValue());
}
public Cookie findCookie(HttpServletRequest request, String cookieName) {
Cookie[] cookies = request.getCookies();
if (cookies == null) {
return null;
}
return Arrays.stream(cookies)
.filter(c -> c.getName().equals(cookieName))
.findAny()
.orElse(null);
}
μ°μ ν΄λΌμ΄μΈνΈμκ² κ°μ Έμ¨ μΏ ν€ λͺ©λ‘μΌλ‘λΆν° λ΄κ° νμλ‘ νλ μΏ ν€λ₯Ό λ½μλ΄μΌ νλ€. κ·Έλ κ² λ½μλΈ μΏ ν€λ‘λΆν° `sessionId`λ₯Ό μ»μ΄λΈλ€. `sessionId`λ₯Ό ν΅ν΄ `Map`μμ `sessionId`μ ν΄λΉλλ μ μ μ 보λ₯Ό κ°μ Έμ¨λ€. κ·Έλ°λ° μμ κ°μ΄ μΈμ
μ μ§μ μΌμΌν ꡬννλ κ²μ μλΉν λΆνΈνλ€. κ°λ°μλ€μ λΆνΈν κ²μ μ λλ‘ μ’μνμ§ μλλ€. λ°λΌμ μλΈλ¦Ώλ κ°νΈνκ² κ°λ°ν μ μλλ‘ μΈμ
μ체λ₯Ό μ§μνλ€.
μλΈλ¦Ώμ΄ μ 곡νλ HttpSession
μλΈλ¦Ώμ μΈμ μ μ 곡νκΈ° μν΄ `HttpSession`μ μ 곡νλ€. `HttpSession`μ μ§μ ꡬνν μΈμ κ³Ό λμΌν κΈ°λ₯μ **μΆκ°μ μΌλ‘ μΌμ μκ° μ¬μ©νμ§ μμΌλ©΄ μμ λλ κΈ°λ₯μ μ 곡νλ€.** μλΈλ¦Ώμ ν΅ν΄ `HttpSession`μ μμ±νλ©΄ `JSESSIONID`λΌλ μ΄λ¦μ κ°μ§ μΏ ν€λ₯Ό μμ±νλ€. μΈμ μ μμ±νλ λ°©λ²μ μμ보μ.
loginController.java
//μΈμ
μ΄ μμΌλ©΄ μλ μΈμ
λ°ν, μμΌλ©΄ μ κ· μΈμ
μ μμ±
HttpSession session = request.getSession(/*create μ΅μ
*/);
session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember);
μ°Έκ³ ) create μ΅μ
1. true (default) : μΈμ μ΄ μμΌλ©΄ μλ‘μ΄ μΈμ μ μμ±ν΄μ λ°ν
2. false : μΈμ μ΄ μμΌλ©΄ μλ‘μ΄ μΈμ μ μμ±νμ§ μκ³ `null`μ λ°ννλ€.
μΈμ
μ μμ± νμΌλ μΈμ
μ μ¬μ©νλ λ°©λ²μ μμ보μ.
homeController.java
HttpSession session = request.getSession(false);
Member loginMember = (Member)session.getAttribute(SessionConst.LOGIN_MEMBER);
μλΈλ¦Ώμμ μ 곡νλ HttpSessionμ ν΅ν΄ μΈμ
μ ꡬννλ λ°©λ²μ μμλ΄€λ€. μ΄μ λ λ§μΌλ‘λ μΆ©λΆνμ§λ§ Springμ μ¬κΈ°μ λ λμκ°μ μ’ λ νΈλ¦¬νκ² μΈμ
κΈ°λ₯μ ꡬνν μ μλλ‘ @SessionAttributeλ₯Ό μ§μνλ€.
homeController.java
public String homeLoginV3Spring(
@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember, Model model) {
model.addAttribute("member", loginMember);
...
}
TrackingModes
λ‘κ·ΈμΈμ μ²μ μλνλ©΄ URL λ€μ `JSESSIONID`κ° ν¬ν¨λμ΄ μλ κ²μ λ³Ό μ μλ€.
http://localhost:8080....../;jsessionid=...
μ΄κ²μ μΉ λΈλΌμ°μ κ° μΏ ν€λ₯Ό μ§μνμ§ μμ λ, μΏ ν€ λμ μ URLμ ν΅ν΄μ μΈμ
μ μ μ§νλ λ°©λ²μ΄λ€. μ΄ λ°©λ²μ ν΅ν΄ μΏ ν€λ₯Ό μ§μνκΈ° μν΄μλ λͺ¨λ URL λ€μ `JSESSIONID`λ₯Ό ν¬ν¨νμ¬ μ λ¬ν΄μΌ νλ€. 볡μ‘ν λ°©λ²μ΄λΌ μ μ¬μ©νμ§ μλλ€. μλ² μ
μ₯μμλ λΈλΌμ°μ κ° μΏ ν€λ₯Ό μ§μ νλμ§ μνλμ§ μμ§ λͺ»νκΈ° λλ¬Έμ μ²μμ 무μμ URLμ `JSESSIONID`λ₯Ό ν¬ν¨νμ¬ μ λ¬νλ κ²μ΄λ€.
λ¬Όλ‘ μμ μ΅μ
μ μλμ κ°μ μ€μ μ ν΅ν΄ μμ¨ μ μλ€.
application.proerties
server.servlet.session.tracking-modes=cookie
μΈμ νμμμ μ€μ
λ³΄ν΅ λ‘κ·Έμμμμ session.invalidate()κ° νΈμΆλμ΄ μΈμ
μ΄ μμ λλ€. κ·Έλ°λ° λ³΄ν΅ μ¬μ©μλ€μ λ‘κ·Έμμ λ²νΌμ λλ₯΄μ§ μκ³ λΈλΌμ°μ μ체λ₯Ό μ’
λ£ν΄λ²λ¦°λ€. HTTPλ stateless νλ‘ν μ½μ΄κΈ° λλ¬Έμ μλ² μ
μ₯μμλ μ¬μ©μκ° λΈλΌμ°μ λ₯Ό μ’
λ£ν κ²μ μμ§ λͺ»νλ€.
μ΄λ κ² λλ©΄ μλ²μμ μΈμ
μ λ©λͺ¨λ¦¬μ μ μ₯νμ¬ κ΄λ¦¬νλλ°, μμ², μλ§λͺ
μ μΈμ
μ΄ κ³μ μμ΄κ² λμ΄ μλ²κ° ν°μ Έ λ²λ¦΄μλ μλ€. λν 무νμ λ¨μμλ μΏ ν€λ₯Ό ν΄μ»€μκ² νμ·¨ λΉν΄ μ
μμ μΈ μμ²μ λΉν μ μλ€. λ°λΌμ μΈμ
μ μΌμ μκ°μ΄ μ§λλ©΄ μλμΌλ‘ μμ λλλ‘ μ²λ¦¬ν΄μΌλ§ νλ€.
μ°Έκ³ )
μΈμ μ μ λ§ μ΅μνμ λ°μ΄ν°λ§ 보κ΄ν΄μΌ νλ€. μ μ μκ° λ§μμ§κ² λλ©΄ μΈμ λλ¬Έμ λ©λͺ¨λ¦¬ μ©λμ λ²μ΄λκ² λμ΄ μ λ§λ‘ μλ²κ° ν°μ§μλ μκΈ° λλ¬Έμ΄λ€.
κ·Έλ λ€λ©΄ μΈμ μ μΈμ μ’ λ£μμΌμΌ ν κΉ?
λ§μ½ κ°λ¨νκ² μΌμ μκ°λ§λ€ μΈμ
μ μμ μν€λ©΄ κ³μ μ¬μ©νλ μ¬μ©μλ κ°μκΈ° λ‘κ·Έμμ λλ λΆνΈν μν©μ λ§μ΄νκ² λ κ²μ΄λ€. κ·Έλ λ€λ©΄ μ΄λ€ μμ μ μ’
λ£ν΄μΌ μ¬μ©μκ° λΆνΈν¨μ λλΌμ§ μκ²λ μΈμ
μ μ’
λ£μν¬ μ μμκΉ? httpSessionμ defaultλ‘ μ¬μ©μκ° μλ²μ μμ²ν μκ°μ κΈ°μ€μΌλ‘ μκ°μ κ³μ°νμ¬ μ’
λ£νλ€. μλͺ
μ£ΌκΈ° μ€μ λ²μ μμ보μ, κΈλ‘λ²ν μ€μ λ²κ³Ό μΈμ
λ§λ€ μ€μ ν μ μλ μ€μ λ²μ΄ μλλ° μ°μ κΈλ‘λ² μ€μ λ² λΆν° μμ보μ.
application.properties
server.servlet.session.timeout=1800 (1800μ΄)
λ€μμ νΉμ μΈμ
λ§ μ§μ νλ κ²½μ°μ΄λ€.
session.setMaxInactiveInterval(1800);
1800μ΄λ‘ μ§μ νκ² λλ©΄ μ΅κ·Ό μΈμ
μ κ·Ό μκ° (`LastAccessedTime`) μ΄νλ‘ 1800μ΄ μκ°μ΄ μ§λλ©΄, WASκ° μΈμ
μ μ κ±°νλ€. λ§μ½μ 1800μ΄ μ μ μ¬ μμ²μ νκ² λλ©΄ κ·Έ μμ λΆν° λ€μ 1800μ΄λ₯Ό κ³μ°νκ² λλ€.
μΆμ²
Inflearn μ€νλ§ MVC 2νΈ - λ°±μλ μΉ κ°λ° νμ© κΈ°μ - κΉμνλ κ°μλ₯Ό μκ°νλ©° μ 리ν λ΄μ©μ
λλ€