로그인할때 다음 로그인시 아이디를 기억하겠냐는 체크박스를 구현해보자
쿠키와 세션의 개념을 먼저 보자
서버는 브라우저가 처음 방문했을때 ( 쿠키가 없다면 ) 세션을 생성하여 응답헤더에 주고 자신의 세션저장소에도 저장한다음 다음 연결시 요청헤더의 쿠키( 세션 ID - key )와 세션저장소의 세션을 비교해서 동일한 연결( 동일한 브라우저 )이라 판단한다.
기본적으로 방문에 대한 기록을 남기는 쿠키도 있겠지만 로그인상태에 관한 쿠키도 존재한다.
메모리 쿠키라면 브라우저 종료시 서버에 저장된 세션 id는 소멸
브라우저는 쿠키를 자동저장하게 만들어져 있다. 앱개발자는 쿠키를 저장하는 기능을 만들어야 한다.
쿠키를 사용할때는 Null인지 확인부터 - NullPointer익셉션 발생함
( 쿠키의 수명은 setMaxAge()
로 설정 )
쿠키는 도메인별로 관리된다 - 접속한 도메인에서만 쿠키를 받고 보낸다.
세션은 클라이언트의 상태를 저장해서 상태를 저장하지 않는 stateless
한 http를 stateful
로 만들어주는 기술
서버는 응답헤더의 쿠키헤더( Set-cookie
)에 쿠키를 넣어서 리턴
-> JSESSIONID
의 값으로 세션의 ID ( key ) 를 브라우저와 공유
세션저장소에 유저 오브젝트를 저장( value )하고 요청헤더의 쿠키( JSESSIONID )와 비교해서 로그인상태 확인 - 인증
세션저장소에 세션은 ( key-value 구조
)로 저장됨
로그인세션은 로그아웃시 삭제됨 ( invalidate()
)
로그인과 상관없이 브라우저 세션도 저장함 ( 단순 방문 )
세션의 값은 오직 서버에만 존재하기 때문에 보안에 좋다
모든 유저의 세션을 저장하면 서버부하가 커진다 - 토큰으로 보완
<form action="/login" method="post">
<input type="text" name="username" placeholder="Enter username" required><br />
<input type="password" name="password" placeholder="Enter password" required><br />
유저네임을 기억할까요? <input type="checkbox" name="remember"><br />
<button type="submit">로그인</button>
</form>
체크박스의 속성 이름은 remember
value를 정하지 않으면 체크 시 디폴트값은 on
체크를 하지 않으면 value값은 null
addHeader
- 헤더에 데이터 추가
@PostMapping("/login")
public String login(String username, String password,
String remember, HttpServletResponse response) {
User user = userRepository.findByUsernameAndPassword(username, password);
response.addHeader("hello", username);
if (user == null) { // 로그인 실패시
return "redirect:/loginForm";
} else {
session.setAttribute("principal", user);
return "redirect:/";
}
}
response.addHeader("hello", username);
-> 입력받은 username 을 응답헤더에 넣었다.
브라우저에서 응답헤더를 확인해보면 hello : ssar
을 확인할수 있다.
🔥 addHeader
의 단점
아래와 같이 작성했다면 hello로 한번에 하나만 꺼낼 수 있을까 ?
response.addHeader("hello", username);
response.addHeader("hello", "member");
setHeader - 헤더 덮어쓰기
response.addHeader("hello", username);
response.setHeader("hello", "test3");
addCookie - 쿠키 추가
@PostMapping("/login")
public String login(String username, String password,
String remember, HttpServletResponse response) {
User user = userRepository.findByUsernameAndPassword(username, password);
if (user == null) { // 로그인 실패시
return "redirect:/loginForm";
} else {
if( remember == null){ // 체크 안하면 null, 공백 넣어서 비교
remember = "";
}
if( remember.equals("on")){
Cookie cookie = new Cookie("remember", username); // 쿠키 생성
response.addCookie(cookie);
}else{
Cookie cookie = new Cookie("remember", "");
cookie.setMaxAge(0);
response.addCookie(cookie);
}
session.setAttribute("principal", user);
return "redirect:/";
}
}
response.addCookie(cookie);
-> 응답헤더( Set-Cookie )에 생성한 쿠키를 추가
로그인 후 응답헤더에 쿠키추가 됨
2개의 쿠키가 브라우저에 저장
다음 요청부터 요청헤더 쿠키에 remember=ssar
이 추가됨
서버 종료후 다시 시작( 세션이 소멸했다고 가정 )해도 브라우저는 remember=ssar
쿠키를 가지고 있다
이것을 이용해서 다음에 로그인시 아이디를 기억하게 만들 수 있다.
EL 표현식은 쿠키에도 접근이 가능하다
( page, request, session, cookie 접근 가능 )
<form action="/login" method="post">
<input type="text" name="username" value="${cookie.remember.value}"
placeholder="Enter username" required> <br/>
<input type="password" name="password" placeholder="Enter password" required> <br/>
유저네임을 기억할까요? <input type="checkbox" name="remember"> <br/>
<button type="submit">로그인</button>
</form>
value="${cookie.remember.value}"
를 사용해서
쿠키중에서 키가 remember
인 value ( ssar
) 를 로그인창에 미리 입력
value="${cookie.remember.value}"
를 사용하지 않고 value="${remember}"
로 하는 방법 Cookie[] cookies = request.getCookies(); // getCookies쿠키 목록 배열 리턴
String username="";
for (Cookie cookie : cookies) {
if (cookie.getName().equals("remember")){
username = cookie.getValue();
}
}
model.addAttribute("remember", username);
getCookies
-> 쿠키 배열 리턴 / Model 에 넣어서 접근
로그아웃시 세션 제거 - session.invalidate()
다시 로그인시 응답헤더에 새로운 쿠키 보급
로그인 세션으로 판단
<c:choose>
<c:when test="${principal == null}">
<li>
<a href="/">홈</a>
</li>
<li>
<a href="/loginForm">로그인</a>
</li>
<li>
<a href="/joinForm">회원가입</a>
</li>
</c:when>
<c:otherwise>
<li>
<a href="/">홈</a>
</li>
<li>
<!-- /user/1/purchase -->
<a href="/purchase">구매목록</a>
</li>
<li>
<a href="/logout">로그아웃</a>
</li>
</c:otherwise>
</c:choose>
<c:when test="${principal == null}">
는 if문과 동일 - true일 경우principal
은 세션에 저장된 유저 오브젝트 ( 존재하면 true )<c:otherwise>
false 일 경우"/userloginForm"
❎
로그인 하면 구매버튼 보이게 설정
<!-- 세션에 principal 존재하면 보이게 -->
<c:if test="${principal != null}">
<form action="/purchase/insert" method="post">
<div class="purchase_btn">
<div>
<input type="hidden" name="productId" value="${product.id}">
<select name="count">
<c:forEach begin="1" end="${product.qty}" var="num">
<option value="${num}">${product.name} ${num} 개</option>
</c:forEach>
</select>
</div>
<div>
</div>
<button type="submit"> 구매 </button>
</div>
</form>
</c:if>