일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- jwt example
- springboot mongodb config
- angular jwt
- springboot-angular-jwt
- jvm 모델
- spring jwt
- mongodb install ec2
- springboot maven plugin
- docker mongodb
- jvm memory structure
- spring-boot-maven-plugin
- string comparison
- Constants pool
- docker mongodb install
- jvm 메모리 구조
- spring filter ordering
- install mongodb docker
- springboot jwt example
- String Pool
- String Constants Pool
- HHH000104
- JWT
- jwt token
- JPA
- intern
- 기본 Manifest 속성이 없습니다
- springboot jwt
- jpa pagination
- jvm memory model
- filter ordering
- Today
- Total
개발블로그
HttpSession은 "언제" 만들어질까? 본문
이 글에서 알 수 있는 내용
-Tomcat은 WAS? No! Just Servlet Container!
-HttpSession은 언제 만들어질까?
-HttpSession을 사용하는 방법
-Session은 어떻게 유지될까?
[Tomcat은 WAS? No! Just Servlet Container!]
JAVAEE는 엔터프라이즈 어플리케이션을 위해 만든 표준이고, 수많은 클래스/인터페이스로 정의되어 있습니다. JAVAEE 6.0의 스펙을 보면, Web Services, Web Application, Enterprise Application, Management and Security 기술들을 정의하고 있습니다. 그리고 이 스펙을 모두 구현한 모델을 WAS라고 칭합니다.
우리가 흔히 WAS로 알고 있는 tomcat은 JAVAEE 스펙의 일부만 구현하고 있어, WAS가 아니라 Servlet Container 입니다.
tomcat 공식 문서에는 다음과 같은 내용이 명시되어 있습니다.
This is the top-level entry point of the documentation bundle for the Apache Tomcat Servlet/JSP container. Apache Tomcat version 9.0 implements the Servlet 4.0 and JavaServer Pages 2.3 specifications
우리가 웹어플리케이션을 개발할 때 사용한 HttpSession도 Servlet Container가 생성한 인스턴스입니다. Spring Web MVC를 이용해서 구현한다 할지라도 Spring은 Servlet Container가 만든 HttpSession을 주입할 뿐, HttpSession을 생성하는 주체는 Servlet Container입니다.
(참고로 SpringSession을 이용한다면 Servlet Container가 생성한 구현체가 아니라 SpringSession이 생성한 구현체가 될 것입니다.
SpringSession은 Servlet Container가 아닌 Redis나 Mongodb같은 데이터베이스에 세션을 저장/관리하기 위해 API를 제공합니다. )
[HttpSession은 언제 만들어질까?]
HttpSession을 Servlet Container가 만드는건 알겠는데, 그럼 언제 만들어질까요?
모든 요청에 대해 Session을 만들까요?
아닙니다. Session을 만드는 것 자체도 부담이 가는 일이기 때문에, Session을 사용할 때만 생성합니다.
Spring Web MVC에서는 HttpSession을 주입해야 할 때, 내부적으로 Servlet Container에게 Session을 달라고 합니다.
1
|
httpServletRequest.getSession()
|
cs |
그리고 그 때 Servlet Container가 HttpSession을 생성해줍니다. Spring이 Servlet Container에게 Session을 달라고 하는 시점은 HttpSession을 사용하는 방법에 따라 약간씩 다릅니다.
[HttpSession을 사용하는 방법]
1. @Autowired로 주입받는 방식.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@RestController
public class LoginController {
@Autowired
private HttpSession session;
@PostMapping("login")
public ResponseEntity<ResponseMessage> login(@RequestBody User user) {
// TODO 일치하는지 확인하는 logic 추가
session.setAttribute("LOGIN_USER", user);
return ResponseEntity.ok(new ResponseMessage(true));
}
}
|
cs |
HttpSession을 주입받는다고 선언하는 것만으로는 Servlet Container에게 Session을 달라고 요청하지 않습니다. setAttribute 혹은 getAttribute 같은 api를 호출하는 시점에 요청/생성합니다.
(참고로 LoginController와 HttpSession의 스코프 차이 때문에 Spring이 HttpSession 인스턴스를 동적 프록시로 생성하여 주입해줍니다. 이것을 Scoped Proxy라고 합니다. LoginController는 singleton scope를 가지며, HttpSession은 session scope를 가집니다.)
2. 메소드에서 주입받는 방식.
1
2
3
4
5
6
7
8
9
10
11
|
@RestController
public class LoginController {
@PostMapping("login")
public ResponseEntity<ResponseMessage> login(@RequestBody User user, HttpSession session) {
// TODO 일치하는지 확인하는 logic 추가
session.setAttribute("LOGIN_USER", user);
return ResponseEntity.ok(new ResponseMessage(true));
}
}
|
메소드에서 매개변수를 통해 주입받는 방식으로 구현한다면, 선언시에 Servlet Container에게 Session을 달라고 요청합니다. 따라서 위의 예제에서는 login 메소드를 호출하는 즉시 Session이 요청/생성됩니다.
3. @SessionAttribute, @ModelAttribute로 주입받는 방식.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Controller
@SessionAttributes("todos")
public class TodoController{
@GetMapping("/form")
public String showForm(Model model, @ModelAttribute("todos") TodoList todos){
if(!todos.isEmpty()){
model.addAttribute("todo", todos.peekLast());
} else {
model.addAttribute("todo", new TodoItem());
}
return "sessionattributesform";
}
|
cs |
이 방식은 Session에 이미 저장된 데이터를 조회할 때 적합하므로 로그인을 처리하는 로직과는 어울리지 않습니다. 그래서 Baeldung의 예제를 첨부했습니다.
2라인 : @SessionAttributes를 컨트롤러에 추가함으로써 세션 단위로 스코프를 지정하도록 명시해줍니다.
6라인 : @ModelAttribute을 선언함으로써 Session에서 "todos"라는 키를 가진 값을 조회합니다. 그리고 TodoList로 변환해 todos 파라미터로 주입해줍니다.
이 방식도 선언시에 Servlet Container에게 Session을 달라고 요청하기 때문에 showForm 메소드를 호출할 때 Session이 요청/생성됩니다.
[Session은 어떻게 유지될까?]
위와 같이 구현하면, HttpSession을 필요로 하는 모든 요청에 대해서(Header에 특별한 키가 없다면) 새로운 Session을 발급해 줍니다.
Tomcat의 경우 이 SessionID를 JSESSIONID라는 키의 쿠키로 생성/전달합니다.
따라서 로그인 이후의 플로우처럼 세션을 유지하기 위해서는
- 서버의 로그인로직에서 로그인이 성공하면 발급받은 SessionId를 클라이언트에게 돌려주고,
- 클라이언트는 이후 요청을 할 때, 서버로부터 받았던 SessionId를 함께 넘겨줍니다.
- Servlet Container에서는 Request에 SessionId가 있으면 Session을 새로 발급하지 않고 전달받은 SessionId와 매핑되는 기존의 Session을 할당해줍니다.
코드와 함께 살펴보겠습니다.
1. 브라우저에서 로그인 요청을 보냅니다.
2. 서버에서는 로그인 정보가 일치하면 세션을 생성해주고, 그 세션에 Key-Value형식으로 로그인 정보를 저장한다.
다음 코드에서는 로그인 정보가 일치하는지 확인하는 로직은 생략했고, 일치한다는 가정하에 작성했습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@RestController
public class LoginController {
@Autowired
private HttpSession session;
@PostMapping("login")
public ResponseEntity<ResponseMessage> login(@RequestBody User user) {
// TODO 일치하는지 확인하는 logic 추가
session.setAttribute("LOGIN_USER", user);
return ResponseEntity.ok(new ResponseMessage(true));
}
}
|
cs |
10라인에서 Session을 사용하므로, 이 때 Servlet Container로부터 Session을 발급받습니다.
3. Servlet Container는 현 요청에서 Session을 사용하고 있으면, HttpResponse의 쿠키에 JSESSIONID 키로 SessionID를 넣어줍니다.
저는 postman에서 테스트했고, 아래 그림은 postman에서 요청을 보냈을 때의 응답 정보입니다.
Set-Cookies에 JSESSIONID가 추가되어있음을 확인할 수 있습니다.
4. 브라우저는 Cookie에 담긴 정보를 그대로 다음 요청의 Cookie에 넣어줍니다.
postman에서도 브라우저와 동일하게 동작합니다.
5. 이후 요청부터는 Cookie에 JSESSIONID 값이 들어가 있을 것입니다.
Servlet Container에서는 Cookie에 JSESSIONID가 있음을 확인하고, 새로운 Session을 만들지 않고 JSESSIONID의 value값과 매핑되는 기존의 Session을 연결해줍니다.
HttpSession은 Server 내부 자원(메모리, 디스크 등)을 사용하므로 일정 시간동안 사용되지 않으면 자원 해제가 되며 이를 Session 만료(expiration)라고 합니다. HttpSession 만료 시간 설정은 servlet-session-timeout을 참고하시기 바랍니다.
Session이 만료된 경우, Session을 생성하기 위해 다시 위 절차를 따릅니다.
전체 소스는 github에 등록되어있습니다.
'Spring' 카테고리의 다른 글
Springboot-Angular-JWT기반 A/A기능 구현(1) (0) | 2019.03.28 |
---|---|
JWT(Json Web Token)란? (0) | 2019.03.13 |
Spring-security authorizeRequest 동적으로 설정하기 (0) | 2019.02.28 |
Authentication/Authorization 기능 구현(2) - interceptor vs spring security (0) | 2019.01.24 |
Authentication/Authorization 기능 구현(1) - interceptor vs spring security (0) | 2019.01.03 |