본문 바로가기

TIL

TIL 240625 Session

Session이란

- 서버에서 중요한 정보를 보관하며 로그인 연결을 유지하는 방법

 

Cookie는 중요한 정보를 Client측에서 보관하고 있는 것

 

Session의 동작 방식

로그인에 성공하면 Server에서 임의로 만든 Session ID를 생성한다

 - Session ID는 예측이 불가능해야 한다

 - 이미 사용해보았던 UUID와 같은 값을 활용한다

 

생성된 Session ID와 조회한 User 인스턴스를 서버의 Session 저장소에 저장한다

 - 서버에 유저와 관련된 중요한 정보를 저장한다

 

 

실제 동작방식

1. 로그인

결국 Session ID로 연결 상태유지를 위해 Cookie를 사용한다

 - 서버는 클라이언트에 Set-Cookie : SessionId = 임의생성값 을 전달한다

 - 클라이언트는 Cookie 저장소에 전달받은 값을 저장한다

세션의 아주 중요한 포인트는 유저와 관련된 정보는 클라이언트에 없다는것

 

 

2. 로그인 이후 요청

- 클라이언트는 모든 요청에 SessionId Cookie를 전달한다

- 서버에서는 쿠키를 통해 전달된 SessionId로 Session 저장소를 조회한다

- 로그인시 저장하였던 Session 정보를 서버에서 사용한다

 

정리

  • Session을 사용하여 서버에서 민감한 정보들을 저장하게 되었다.
  1. 예상 불가능한 세션 ID를 사용하여 쿠키값을 변조해도 문제가 없다.
  2. Session ID가 탈취되어도 중요한 정보는 들어있지 않다.
  3. Session ID가 탈취되어도 시간이 지나면 세션이 만료되도록 설정 하면된다.
  4.  Session ID가 탈취되어도 해킹이 의심되는 경우 해당 세션을 제거하면 된다.
  • Session은 특별한것이 아니라 단지 Cookie를 사용하여 클라이언트가 아닌 서버에서 데이터를 저장해두는 방법이다.
  • Session을 코드로 직접 구현할 수는 있지만 모두가 예상할 수 있듯이 당연히 Servlet은 Session 을 자체적으로 지원한다.

Servlet HttpSession

- HttpSession에는 Session 기능 구현에 필요한 많은 기능들을 지원한다

1. Servlet을 통해 HttpSession을 생성하게 되면 위 예시에서 본 SessionId가 JSESSIONID로 생성된다

2. JSESSIONID의 Value는 예측 불가능한 랜덤값으로 생성된다

ex) JSESSIONID = WLRMATLRKSQKA12AZKXNQ

 

코드예시

// 추상클래스 -> 됨
public abstract class Const {
	public static final String LOGIN_USER = "loginUser";
}

// 인터페이스 -> 됨
public interface Const {
	String LOGIN_USER = "loginUser";
}

// 클래스 -> 안됨
public class Const { // new Const();
	public static final String LOGIN_USER = "loginUser";
}

// Const.LOGIN_USER; O / new Const(); X

 

@Getter
public class LoginRequestDto {
	
	@NotBlank	
	private String id; // 사용자가 입력한 아이디

	@NotNull
	private String pwd; // 사용자가 입력한 비밀번호

}

@Controller
@Requiredargsconstructor
public class UserController {

	private final UserService userService;

	@PostMapping("/login")
	public String login(
		@Valid @ModelAttribute LoginRequestDto dto,
		HttpServletRequest request
	) {
		
		User loginUser = loginService.login(dto.getId(), dto.getPwd());
		// 실패시 예외처리		

		// 로그인 성공시 로직
		// Session이 request에 존재하면 기존의 Session을 반환하고, 
		// Session이 request에 없을 경우에 새로 Session을 생성한다.
		HttpSession session = request.getSession(); // default true => session 생성
		
		// Session에 로그인 회원 정보를 저장한다.
		session.setAttribute(Const.LOGIN_USER, loginUser);
		
		// 로그인 성공시 리다이렉트
		return "redirect:/";
	}
}

 

  • request.getSession();
    • default 값은 true 이다.
  • request.getSession(true);
    • Request 객체 내에 Session이 존재한다면 기존 Session을 반환
    • Request 객체 내에 Session이 없으면 새로운 Session을 생성해서 반환
    • Default
  • request.getSession(false);
    • Request 객체 내에 Session이 존재한다면 기존 Session을 반환
    • Request 객체 내에 Session이 없으면 null을 반환
  • session.setAttribute(Const.LOGIN_USER, loginUser);
    • Session에 Data를 저장하는 방법 전에 배운 request.setAttribute(); 와 비슷함
    • 하나의 Session에 여러개의 데이터를 메모리에 저장할 수 있다.

로그아웃

@Controller
@Requiredargsconstructor
public class UserController {

	private final UserService userService;

	@PostMapping("/logout")
	public String logout(
		HttpServletRequest request
	) {
		
		HttpSession session = request.getSession(false);
		// 세션이 존재하면 -> 로그인이 된 경우
		if(session != null) {
			session.invalidate(); // 해당 세션(데이터)을 삭제한다.
		}
		
		return "redirect:/";
	}
}

 

  • 로그인 후 사용할 API
    • 요구사항
      • 로그인한 회원이면 home 페이지로 이동(”home” 페이지를 보려면 로그인 필수)
      • 로그인하지 않은 회원이면 login 페이지로 이동
@Controller
@Requiredargsconstructor
public class HomeController {

	private UserService userService;
	
	@GetMapping("/")
	public String home(
		HttpServletRequest request,
		Model model		
	) {
		
		// default인 true로 설정되면 로그인하지 않은 사람들도 값은 비어있지만 세션이 만들어진다.
		// session을 생성할 의도가 없다.
		// session은 Memory를 사용하기 때문에 막 사용하면 안된다! 리소스 낭비!
		request.getSession(false);
		
		// session이 없으면 로그인 페이지로 이동
		if(session == null) {
			return "login";
		}
		
		// session에 저장된 유저정보 조회
		// Object loginUser = session.getAttribute(Const.LOGIN_USER);
		
		// 반환타입이 Object여서 Type Casting이 필요하다.
		User loginUser = (User)session.getAttribute(Const.LOGIN_USER);

		// Session에 유저 정보가 없으면 login 페이지 이동
		if (loginUser == null) {
			return "login";
		}

		// Session이 정상적으로 조회되면 로그인된것으로 간주
		model.addAttribute("loginUser", loginUser);
		// home 화면으로 이동
		return "home";
		
	}
}

 

 

 

'TIL' 카테고리의 다른 글

TIL 240624 Cookie  (0) 2024.06.25
TIL 240621 Validation  (0) 2024.06.24
TIL 240617 과제 피드백 AOP  (0) 2024.06.18
TIL 240614 Mockito, 통합테스트  (0) 2024.06.17
TIL 240613 단위 테스트  (1) 2024.06.14