본문 바로가기
백엔드/웹 개발

방문자 기억 - (세션/쿠키)

by study_yeon 2023. 6. 28.

2023.06.27 수업


● 웹 개발 3장

※ 세션과 필터

- 웹은 과거의 상태를 유지하지 않는 무상태(stateless)
-> 기존 사용자에 대한 정보를 기억하지 않음
- 세션과 쿠키는 웹의 단점(Connection less) 극복

* 세션 트랙킹 
- 로그인 유지를 위한 모든 기능
- 방문 기록을 추적하는 기법
- HTTP에서는 쿠키 이용

 

▶ 쿠키

- 문자열로 만들어진 데이터 조각

- 서버와 브라우저 사이에서 요청이나 응답시에 주고받는 형태

- '이름', '값'의 구조

- 브라우저 개발자도구의 애플리케이션에서 확인

* 쿠키 생성하는 법
1. 서버에서 자동 생성
- WAS마다 고유한 이름을 사용해서 쿠키를 생성, 톰캣은 JSESSIONID 이용
- 브라우저의 메모리상에 보관하여 브라우저를 종료하면 쿠키가 삭제됨
- '/'의 경로로 지정됨
- 이전 내용을 보관하고 싶다면 파일로 만들어 저장하기(개발자 쿠키)

2. 개발자가 생성하는 쿠키
- 이름을 원하는대로 지정
- 유효기간(setMaxAge) 지정(브라우저가 파일의 형태로 보관)
- 직접 응답(response)에 추가
- 경로나 도메인을 지정할 수 있음


▶ 서블릿 컨텍스트와 세션 저장소

- 사용하고 있는 서버는 톰캣

- 하나의 톰캣은 여러 개의 웹 애플리케이션(웹 프로젝트)를 실행할 수 있고, 실제 운영의 경우 웹 애플리케이션마다 별도의 도메인으로 분리하여 운영

ex) /list, /read, /register, /modify


* 서블릿 컨텍스트
- 웹 애플리케이션은 고유의 메모리 영역을 하나 생성하여 이 공간에 서블릿이나 JSP등을 인스턴스로 만들어 서비스를 제공하는 영역

* 세션 저장소
- 웹 애플리케이션을 생성할 때 톰캣이 발행하는 쿠키(세션 쿠키)들을 관리하기 위해 생성된 메모리 영역
- 보안기능을 가짐
- 키와 값을 보관하는 구조
- JSESSIONID(쿠키의 값) : 키가 되는 역할
- 발행된 쿠키의 정보를 보관하는 역할을 하며 JSESSIONID가 만들어질때마다 메모리 공간을 차지하기 때문에 톰캣이 주기적으로 정리해줌

* 세션을 통한 상태 유지 메커니즘


▶ 실습
-  패키지(w2) 새로 만들기
- db는 그대로 사용
- 서블릿/JSP 새로 만들기

* 프로젝트의 생성(패키지 변경)
- 패키지명 org.zerock.w2

* 기존의 todo를 todojdbcex로 변경(해당 Controller의 url도 모두 변경)
- JavaWeb/src/main/webapp/WEB-INF에 앞으로 사용 할 todo 폴더 만들기

▷ 서블릿 만들기
패키지명 org.zerock.w2.controller
클래스명 TodoListController

- 로그인 코드를 구현하지 않음
- WEB-INF폴더로 접근하기 위한 중간역할
- 요청객체를 list.jsp로 넘기기(requestDispatcher, forward)
- get 방식으로 접근

package org.zerock.w2.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.extern.log4j.Log4j2;

@WebServlet(name = "todoListController", value = "/todo/list")
@Log4j2
public class TodoListController extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		log.info("/TodoListCotroller/doGet() 실행 중 ...");
		
		req.getRequestDispatcher("/WEB-INF/todo/list.jsp").forward(req, res);	
	}

}

▷ JSP 만들기
WEB-INF todo폴더에 list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>할일 목록 리스트</h1>
</body>
</html>

○ 세션을 이용한 로그인 체크
- 자동로그인 기능
- 현재 사용자의 공간에 지정된 이름(key)로 객체가 저장되어 있는지 확인하여 로그인

▷ 등록할 때 로그인 체크하기
서블릿 만들기
TodoRegisterController
- get 방식

package org.zerock.w2.controller;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import lombok.extern.log4j.Log4j2;

@WebServlet(name = "todoRegisterController", value = "/todo/register")
@Log4j2
public class TodoRegisterController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       

	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		// HttpSession타입을 이용하여 세션객체가 있으면 로그인 사용자로 처리
		// 세션객체가 없으면 (isNew()이용) 새로운 사용자로 처리
		// 로그 찍기
		log.info("TodoRegisterController/doGet() 실행중 ...");
		/// 세션객체를 얻는 법 : 요청객체(request)에서 getSession()이용
		HttpSession session = req.getSession();
		// session객체가 신규인지 기존인지 확인
        // 1. 기존 JSESSIONID가 없는 새로운 사용자
		if (session.isNew()) { 
			log.info("JSESSIONID 쿠키가 새로 만들어진 사용자");
			res.sendRedirect("/login"); // 로그인 실패 정책
			return; // 요청처리가 완료되었으므로 더이상 진행하면 안됨
					// 메소드 실행 종료(모든 메소드의 실행종료는 return)
		}

		// 2. 기존 JSESSIONID는 있지만 해당세션 컨텍스트에 객체(loginfo)가 없는 경우
		if (session.getAttribute("loginInfo") == null ) {	
			log.info("로그인 정보가 없는 사용자입니다.");
			res.sendRedirect("/login");
			return;
		}
		// 3. JSESSIONID에 'loginInfo' 키가 있는 경우
		// 정상적으로 로그인이 된 경우
		String goUrl = "/WEB-INF/todo/register.jsp";
		req.getRequestDispatcher(goUrl).forward(req, res);

	}

}

-> 실행시 JSESSIONID가 없으면 1번 출력, 있으면 2번 또는 3번 출력이 되며

개발자도구에서 JSESSIONID을 삭제하면 1번이 다시 출력된다

 

* getSession() 

- HttpServletRequest의 메소드

- 브라우저가 보내는 정보를 이용하여 세션저장소에 새로운 공간을 만들거나(쿠키가 없을 경우) 기존에 할당된 공간(쿠키가 있을 경우)에 접근할 객체를 반환함

- 결과물은 세션저장소 내의 공간(세션 컨텍스트, 세션)

* isNew()

- 새로운 공간을 만들어 낸것인지 기존의 공간을 재사용하는지 구분


▷ JSP 만들기
* register.jsp 만들기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>회원 페이지</h1>
    <h2>게시글 작성 페이지</h2>
</body>
</html>

* login.jsp 만들기

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 로그인 페이지</title>
</head>
<body>
<form action="/login" method="post">
	아이디 : <input type="text" name="userId" value="" /><br />
	비밀번호 : <input type="password" name="userPassword" value="" /><br />
	<input type ="submit" value="전송" />
</form>
</body>
</html>

 


▷ 서블릿 만들기

* 로그인 처리 컨트롤러
TodoLoginController

- GET 방식으로는 화면만 볼 수 있게 설정(login.jsp 로 이동)

- POST 방식으로는 파라미터를 수집하고 'userInfo'이름을 이용하여 문자열 저장(나중에 DTO로 변경)

- 로그인에 성공하면 /todo/list로 이동(Redirect)

package org.zerock.w2.controller;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import lombok.extern.log4j.Log4j2;

@WebServlet(name = "todoLoginController", value = "/login")
@Log4j2
public class TodoLoginController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
  
	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		log.info("/TodoLoginController/doGet() 실행 ...");
		req.getRequestDispatcher("/WEB-INF/login.jsp").forward(req, res);
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		log.info("TodoLoginController/doPost() 실행 ...");
		
		// 로그인 요청객체에서 요청 파라미터 분리
		// userId, userPassword
		String userId = null;
		String userPassword = null;
		if(req.getParameter("userId") != null ) {
			userId = req.getParameter("userId");
		}
		if(req.getParameter("userPassword") != null) {
			userPassword = req.getParameter("userPassword");
		}
		// 세션에 저장할 userInfo값
		String userInfo = userId + userPassword;
		// 현재 세션정보를 읽어온다
		HttpSession session = req.getSession();
		
		// 세션에 로그인 정보를 저장한다
		// setAttribute("키",값객체); // 세션에 객체 추가
		// getAttribute("키") // 세션에서 값 읽기
		session.setAttribute("userInfo", userInfo);
		
		// 저장된 세션정보를 가지고 새로운 곳으로 이동
		res.sendRedirect("/todo/list");
	}

}

-> 로그인한 후 /todo/register 주소로 이동하면 정상이동, JSESSIONID를 삭제하면 다시 로그인 페이지로 이동한다.

'백엔드 > 웹 개발' 카테고리의 다른 글

사용자 정의 쿠키(자동로그인)  (0) 2023.07.03
로그인, 로그아웃 구현하기(필터)  (0) 2023.06.29
14 게시판 만들기  (0) 2023.06.27
13 게시판 만들기  (0) 2023.06.27
12 게시판 만들기  (0) 2023.06.26