관심쟁이 영호
[Spring Boot] 쿠키, 세션 본문
오늘은 로그인에서 쿠키 및 세션을 적용해볼 것이다!
목차
- 쿠키란?
- 쿠키구현
- 쿠키의 한계
- 세션이란?
- 세션구현
- 스프링에서의 세션
- 세션의 한계
쿠키란?
- 쿠키는 서버측에서 사용자가 누구인지 알기위한 식별값이다.
- TCP/IP 위의 HTTP 통신이 지속성이 없기 때문에(한번 요청 - 한번 응답 끝) 사용자가 요청했을 때, 서버측에서는 그 사용자가 누구인지 모른다.
- 서버는 사용자가 요청을하면 쿠키를 생성하여 응답에 포함하여 전달한다.
그림으로 살펴보자.
1) 최초의 Request - Response
- 사용자가 서버측에 Post요청을 한다.
- 서버는 회원 저장소에서 로그인 id에 맞는 정보가 있는지 확인한다.
- 없어서 쿠키를 설정하고(Set-Cookie: id=abc) 응답한다.
- 회원은 웹브라우저에 있는 쿠키 저장소에 쿠키를 저장한다.
2) 2번째 요청(쿠키가 유지되었을 때)
- 사용자는 쿠키저장소에 저장되어있는 쿠키를 포함한 요청을 한다.
- 서버는 해당 쿠키가 회원저장소에 있는지 살펴본다.
- 회원저장소에 해당 쿠키가 존재하여 해당 회원에 대한 응답을 해준다.
위의 내용을 보면 서로 지속성이 없는대도 요청자가 누구인지 알 수 있게 되었다!
그럼 Spring에서 해당 쿠키를 어떻게 구현하는지 살펴보자.
먼저 가장 쉬운방법은 컨트롤러에서 쿠키를 생성하여 Response에 담아서 응답해주면 될 것이다!
코드로 쿠키를 생성하여 응답하는 것을 살펴보자.
@PostMapping("/login")
public String loginId(@ModelAttribute User user, HttpServletResponse response) {
if(!loginService.login(user)){
return "login";
}
//쿠키 생성
Cookie idCookie = new Cookie("userId", String.valueOf(user.getUserId()));
//응답에 쿠키 추가
response.addCookie(idCookie);
return "redirect:/";
}
코드 설명:
Cookie idCookie = new Cookie("userId", String.valueOf(user.getUserId()));
- Cookie를 key: "userId" / value: "사용자가 입력한 id" 로 생성한다.
reponse.addCookie(idCookie);
- 응답에 쿠키를 추가한다.
이제 쿠키가 정상적으로 브라우저에 포함이 된지 확인해보자!
Response 내용
쿠키가 Response에 "userId"로 전달된 것이 보인다.
문자가 깨지는 것은 필자가 한글로 쿠키를 전달했기 때문이다!
웹브라우저 Cookie 저장소
Application -> Cookies에 들어가면
key: "userId" / value: "영호" / 그 외 기타 등등
이라는 내용의 쿠키가 저장된 것을 볼 수 있다!
쿠키의 한계
지금까지 알아온 쿠키는 엄청 큰 한계점이 있다!
"만약 사용자가 쿠키의 value값을 '영호' -> '철수' 로 교체하여 보낸다면?"
서버는 철수가 들어온지 알고, 철수에 대한 응답을 할 것이다.
맞다. 쿠키는 사용자의 로컬에 저장되기 때문에 얼마든지 조작 및 변경이 가능하다.
그래서 쿠키를 사용한다면 반드시 변경되어도 상관없는 정보만 포함하여야 한다!
세션이란?
세션은 쿠키의 한계점을 개선한 것이다.
쿠키가 사용자측에서 관리하는 요소라면, 세션은 서버에서 관리하는 요소라고 생각하면 된다!
어떻게 서버에서 관리할까?
- 쉽다. 서버에서 쿠키값을 보내지 않고, 랜덤토큰을 생성하여 사용자에게 보낸다. 서버는 랜덤토큰에 대응하는 실제 값을 관리하는 테이블을 가지고 있다.
- 이제 "abCCDCAD^^&#cd"라는 토큰값을 임의로 고쳐도 다른 사람의 토큰과 겹칠 가능성이 현저히 줄어든다!(거의 0퍼)
그림을 통해서 살펴보자.
살펴보자!
- 사용자가 id와 password로 로그인한다.
- 서버는 해당 id로 회원저장소를 조회한다.
- 조회 내용을 토대로 회원값을 임의의 랜덤값을 만든다!
- 랜덤값을 사용자에게 전달한다.
세션 구현
그럼 세션을 구현해보자!
이전의 쿠키와 달라진 점은 다음과 같다.
- 랜덤값 생성
- 랜덤값과 userId 매핑 테이블 생성
- 유저에게 랜덤값을 Response에 포함하여 전달
코드를 살펴보자!
세션 받기
/**
* 세션 관리
*/
@Component
public class SessionManager {
public static final String SESSION_COOKIE_NAME = "mySessionId";
private Map<String, Object> sessionStore = new ConcurrentHashMap<>();
/**
* 세션 생성
*/
public void createSession(Object value, HttpServletResponse response) {
//세션 id를 생성하고, 값을 세션에 저장
String sessionId = UUID.randomUUID().toString();
sessionStore.put(sessionId, value);
//쿠키 생성
Cookie mySessionCookie = new Cookie(SESSION_COOKIE_NAME, sessionId);
response.addCookie(mySessionCookie);
}
/**
* 세션 조회
*/
public Object getSession(HttpServletRequest request) {
Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME);
if (sessionCookie == null) {
return null;
}
return sessionStore.get(sessionCookie.getValue());
}
/**
* 세션 만료
*/
public void expire(HttpServletRequest request) {
Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME);
if (sessionCookie != null) {
sessionStore.remove(sessionCookie.getValue());
}
}
private Cookie findCookie(HttpServletRequest request, String cookieName) {
if (request.getCookies() == null) {
return null;
}
return Arrays.stream(request.getCookies())
.filter(cookie -> cookie.getName().equals(cookieName))
.findAny()
.orElse(null);
}
}
코드 설명:
대충 3가지의 메소드가 있다.
- 세션 생성
- 세션 찾기
- 세션 제거
세션 생성
세션은 랜덤값을 생성해야 하기 때문에, uuid를 이용하여 생성했다.
생성된 uuid를 이용하여 "sessionStore"라는 매핑 테이블에 저장을 해주고, 사용자에게 쿠키로 넘긴다.
@PostMapping("/login")
public String loginId(@ModelAttribute User user, HttpServletResponse response) {
if(!loginService.login(user)){
return "login";
}
sessionManager.createSession(user, response);
return "redirect:/";
}
이거 또한 복잡하다..
그래서 스프링에서 세션을 아주 편하게 사용할 수 있도록 기능을 제공한다!
스프링에서의 세션
@GetMapping("/")
public String homeLoginV3Spring(
@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false)
User loginUser,
Model model) {
//세션에 회원 데이터가 없으면 home
if (loginUser == null) {
return "home";
}
//세션이 유지되면 로그인으로 이동
model.addAttribute("user", loginuser);
return "loginhome";
}
@SessionAttribute를 이용하면 스프링에서 세션을 아주 편하게 사용할 수 있다.
참고로 해당 어노테이션은 세션을 생성하지 않는다.
@SessionAttribute를 이용하면 세션을 찾아주는 번거로운 과정을 알아서 해주는 것을 볼 수 있다.
그래서 세션생성을 HTTP 서블릿에 구현되어있는 기능을 사용하거나 직접구현한 내용을 사용하자!
HTTP 서블릿의 세션을 적용한 컨트롤러
@PostMapping("/login")
public String loginId(@ModelAttribute User user, HttpServletRequest request) {
if(!loginService.login(user)){
return "login";
}
HttpSession session = request.getSession();
session.setAttribute(SessionConst.LOGIN_USER, user);
return "redirect:/";
}
SeesionConst 내용
public class SessionConst {
public static final String LOGIN_USER = "loginUser";
};
성공!
세션의 한계
세션또한 한계가 있다. 사용자들이 많아지면 서버는 세션 매핑테이블에 계속해서 저장을 해야하는데, 이 테이블 조차 엄청나게 무거워질 수 있다. 그래서 최근에는 JWT 토큰 정책을 사용한다.
이 내용은 다음에 살펴보자!
'Bank-End > Spring Boot' 카테고리의 다른 글
[Spring Boot] 파일 업로드 (0) | 2021.08.03 |
---|---|
[Spring Boot] 인터셉터 ㅣ intercepter (0) | 2021.08.03 |
[Spring Boot + JPA] 로그인 구현하기. (0) | 2021.08.03 |
[Spring Boot] Bean Validation 적용하기 (0) | 2021.08.03 |
[Spring Boot 기초] Ajax란? ㅣ Ajax를 사용하는 2가지 이유 (0) | 2021.04.28 |