[JavaWeb] 6장 서블릿 JSP를 활용해 동적인 웹 애플리케이션 개발하기 - 2
6.2 세션 요구사항 및 실습
http는 클라이언트와 서버가 연결된 후 상태를 유지할 수 없기에 무상태 프로토콜이라고 부른다.
하지만 웹 어플리케이션은 로그인과 같이 상태를 유지할 필요가 있는 요구 사항이 발생한다.
이와 같은 경우에 사용할 수 있는 방법이 쿠키 헤더를 사용하는 방법이다.
쿠키 헤더
일단 set-cookie 헤더를 통해 쿠키를 생성하면 이후 발생하는 모든 요청에 set cookie 로 추가한 값을 Cookie 헤더로 전달하는 방식이다.
보안에 취약하다는 단점이 있다.
세션
서버에 상태값을 저장한 후 클라이언트에 고유한 아이디를 발급해 이 아이디를 set cookie 에 전달하는 방식
세션이 상태를 웹서버에서 관리하는 점만 다르고 http 상태값을 유지하기 위한 값을 전달할 때는 쿠키를 사용
세션은 http 쿠키를 기반으로 동작
6.2.1. 요구사항 구현
실습은 5장에서 구현한 http 웹 서버에서 시작할 수 있다.
혹은 https://github.com/slipp/web-application-server 저장소의
was-step3-controller-refactoring 브런치에서 시작할 수 있다.
구현 메서드
-
String getId()
: 현재 세션에 할당되어있는 고유한 세션 아이디를 반환
-
void setAttribute(String name, Object value)
: 현재 세션에 value 인자로 전달되는 객체를 name 인자 이름으로 저장
-
Object getAttribute(String name)
: 현재 세션에 name 인자로 저장되어있는 객체 값을 찾아 반환
-
void removeAttribute(String name)
: 현재 세션에 name 인자로 저장되어있는 객체 값을 삭제
-
void invalidate(): 현재 세션에 저장되어있는 모든 값을 삭제
요구사항 분리 및 힌트
- 예측할 수 어려운 고유 아이디 생성
-
힌트
UUID uuid = UUID.randomUUID();
-
- 생성한 고유한 아이디를 쿠키를 통해 전달
-
힌트
쿠키는 set cookie 헤더를 통해 전달되며 name1=value1, name2=value2 형태로 전달된다,. 세션 아이디를 전달하는 이름으로 JSESSIONID를 사용한다.
-
- 서버 측에서 모든 클라이언트의 세션 값을 관리하는 저장소 클래스를 추가한다.
-
힌트
HttpSessions 와 같은 이름을 가지는 클래스를 추가한다. 이 클래스는 Map<String HttpSession>와 같은 저장소를 통해 모든 클라이언트별 세션을 관리해야한다. 이 저장소의 키는 앞에서 UUID로 생성한 고유한 아이디이다.
-
- 클라이언트 별 세션 데이터를 관리할 수 있는 클래스를 추가한다.
-
힌트
HttpSession 클래스는 요구사항에 있는 5개의 메서드를 구현해야하며, 상태 데이터를 저장할 Map<String, Object>가 필요하다.
-
6.3 세션 구현
6.3.1 고유한 아이디 생성
세션에서 사용할 고유한 아이디를 생성한다.
public class UUIDTest{
@Test
public void uuid(){
System.out.printLn(UUID.randomUUID());
}
}
테스트 실행 시 UUID 의 형태로 임의의 값이 생성된다.
public class RequestHandler extends Thread {
...
public void run(){
...
if(getSessionId(request.getHeader("Cookie")) == null){
response.addHeader("Set-Cookie", "JSESSION=" + UUID.randomUUID());
...
}
private String getSessionId(String cookieValue){
Map<String, String> cookies =
HttpRequestUtils.parseCookies(CookieValue);
return cookies.get("JSESSIONID");
}
}
구현을 완료한 후 리팩토링할 부분을 찾아본다. ListUserController 코드에서 로그인 여부를 확인하기 위해 쿠키 헤더 값을 활용하는 부분이 점점 증가하고 있다.
쿠키 헤더값을 관련하는 HttpCookie 를 추가하는 것이 좋겠다.
public class HttpCookie {
private Map<String, String> cookies;
HttpCookie(String cookieValue){
cookies = HttpRequestUtils.parseCookies(cookieValue);
}
public String getCookie(String name){
return cookies.get(name);
}
위와 같이 HttpCookie 를 추가한 후 HttpsRequest 에서 HttpsCookie에 접근할 수 있는 메소드를 추가한다.
public class HttpRequest{
...
public HttpCookie getCookies(){
return new HttpsCookie(getHeader("Cookie"));
}
}