본문 바로가기

개발/Java

[JAVA - WEB] 세션(Session)

728x90
반응형
세션

 

세션 역시 웹 페이지들 사이의 공유 정보를 서버에 저장해두고 웹 페이지들을 매개해주는 방법이라는 점에서는 쿠키와 같습니다.
차이점은 쿠키는 보안에 취약하지만, 세션은 서버의 메모리에 생성되어 정보를 저장하므로 보안이 용이하여 웹 페이지에서 사용되는 정보 중에 로그인 정보처럼 보안이 요구되는 정보는 대부분 세션을 이용합니다.
세션은 각 브라우저 당 한개, 즉 사용하당 한 개가 생성됩니다. 단 브라우저를 Chrome 과 Explorer 를 사용하게 된다면 브라우저 별로 생성이 되겠죠?  

 

세션의 특징은 다음과 같습니다.

- 브라우저의 세션 연동은 세션 쿠키를 이용합니다.
- 서버에 부하를 줄 수 있습니다.
- 세션은 유효시간을 가집니다.(기본 유효시간은 30분 입니다)


로그인 상태 유지 기능이나 쇼핑몰의 장바구니 담기 기능 등에 주로 사용됩니다.

 

 

 

세션 실행 과정

 

클라이언트 브라우저가 웹 서버에 요청하면 어떻게 세션이 생성되는지 알아보겠습니다.

1. 브라우저로 사이트에 접속합니다.
2. 서버는 접속한 브라우저에 대한 세션 객체를 생성합니다.
3. 서버는 생성된 세션 id 를 클라이언트 브라우저에 응답합니다.
4. 브라우저는 서버로부터 받은 세션 di 를 브라우저가 사용하는 메모리인 세션 쿠키에 저장합니다.(쿠키 이름 jsessionId)
5. 재접속 시 브라우저는 브라우저는 세션 쿠키에 저장된 세션 id 를 서버에 전달합니다.
6. 서버는 전송된 세션 di 를 이용해 해당 세션에 접근하여 작업을 수행합니다.

세션의 중요한 특징은 브라우저당 한 개씩 생성된다는 점입니다.
브라우저가 서버에 접속하여 브라우저에 저장된 세션 id 를 전송하면 서버는 그 값을 이용해서 해당 브라우저에 대한 세션을 구분하고 각 브라우저에 대한 세션 작업을 수행합니다.

 

 

 

세션 API

 

서블릿에서 세션을 이용하려면 HttpSession 클래스 객체를 생성해서 사용해야 합니다.
HttpSession 객체는 HttpServletRequest 의 getSession() 메서드를 호출해서 생성합니다.

- getSession() or getSession(true) : 기존의 세션 객체가 존재하면 반환하고 없으면 새로 생성합니다.
- getSession(false) : 기존의 세션 객체가 존재하면 반환하고 없으면 null 을 반환합니다.

HttpSession 클래스 메서드

 

반환 타입 메서드 기능
Object getAttribute(String name) 속성 이름이 name 인 속성 값을 Object 타입으로 반환합니다.
해당되는 속성 이름이 없을 경우 null 값을 반환합니다.
Enumeration getAttributeNames() 세션 속성 이름들을 Enumeration 객체 타입으로 반환합니다.
long getCreationTime() 1970년 1월 1일 0시 0초를 기준으로 현재 세션이 생성된 시간까지
경과한 시간을 계산하여 1/1000 초 값으로 반환합니다.
String getId() 세션에 할당된 고유 식별자를 String 타입으로 반환합니다.
int getMaxInactiveInterval() 현재 생성된 세션을 유지하기 위해 설정된 세션 유지 시간을 int 타입으로 반환합니다.
void invalidate() 현재 생성된 세션을 소멸합니다.
boolean isNew() 최초로 생성된 세션인지 기존에 생성되어 있었던 세션인지 판별합니다.
void removeAttribute(String name) 세션 속성 이름이 name 인 속성을 제거합니다.
void setAttribute(String name, Object obj) 세션 속성 이름이 name 인 속성에 속성 값으로 value 를 할당합니다.
void setMaxInactiveInterval(int interval) 세션을 유지하기 위한 세션 유지 시간을 초 단위로 설정합니다.

 

메서드 사용 예시입니다.

 

...
HttpSession session = request.getSession();
out.println("세션 아이디 : " + session.getId() + "<br>");
out.println("최초 세션 생성 시간 : " + new Date(session.getCreationTime()) + "<br>");
out.println("최근 세션 접근 시간 : " + new Date(session.getLastAccessedTime()) + "<br>");
out.println("기존 설정 세션 유효 시간 : " + session.getMaxInactiveInterval() + "<br>");
session.setMaxInactiveInterval(5);
out.println("다시 설정 세션 유효 시간 : " + session.getMaxInactiveInterval() + "<br>");
if (session.isNew()) {
    out.print("새로운 세션 생성.");
}
session.invalidate(); // 세션 삭제
...

 

웹 브라우저로 요청하면 각 함수 별로 반환 값을 확인하실 수 있습니다.

 

 

함수 마지막 부분에 invalidate 로 계속 세션을 삭제하기 때문에 새로운 세션이 계속 생성되고 삭제되고가 반복 되네요..

 

 

 

encodeURL 

 

브라우저에서 쿠키를 사용할 수 없게 된다면 세션도 사용할 수 없습니다.

사용자가 모든 쿠키를 다 차단해 버리면 둘다 사용할 수 없게 되버리는거죠.

 

그럴 경우에 encodeURL() 메서드를 이용해 직접 서버에서 브라우저로 응답을 먼저 보낸 후 URL Rewriting 방법을 이용해 jsessionId 를 서버로 전송하여 세선 기능을 사용하면 됩니다.

(URL Rewriting 방법은 보안에 취약하여 로그인 정보 등의 중요한 정보를 보내기에는 부적합한 방법이지만 쿠키랑 세션을 모두 사용할 수 없으니 어쩔수 없겠죠..)

 

...
session.setAttribute("user_id", user_id);
String url=response.encodeURL("login");
out.println("<a href="+url+">로그인 정보 전송</a>");
...

 

 

 

세션을 이용한 회원 로그인

 

기존에 만들었던 데이터베이스를 연동하여 로그인 한 후 세션을 이용해 로그인 상태를 유지하는 것에 알아보겠습니다.

 

먼저 로그인 화면을 보여줄 HTML 을 작성합니다.

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인창</title>
</head>
<body>
	<form name="frmLogin" method="post" action="login" encType="UTF-8">
		아이디  :<input type="text" name="user_id"><br>
		비밀번호 :<input type="password" name="user_pwd"><br>
		<input type="submit" value="로그인">
		<input type="reset" value="다시입력">
	</form>
</body>
</html>

 

로그인 정보가 데이터베이스에 저장된 정보와 일치하는지 확인하는 부분을 memberDAO 에 추가합니다.

 

public boolean isExisted(MemberVO memberVO) {
		boolean result = false;
		String id = memberVO.getId();
		String pwd = memberVO.getPwd();
		try {
			con = dataFactory.getConnection(); 
			// 존재하면 true 없으면 false
			String query = "select decode(count(*),1,'true','false') as result from t_member";
			query += " where id=? and pwd=?";
			System.out.println(query);
			pstmt = con.prepareStatement(query); // 쿼리 할당
			pstmt.setString(1, id); // 파리미터 1 할당
			pstmt.setString(2, pwd); // 파라미터 2 할당
			ResultSet rs = pstmt.executeQuery(); // 쿼리 실행
			rs.next(); // 첫번째 레코드로 이동
			result = Boolean.parseBoolean(rs.getString("result")); 
			System.out.println("result=" + result);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

 

로그인 정보에 대한 처리를 진행할 LoginServlet 를 작성합니다.

 

@WebServlet("/login")
public class LoginServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doHandle(request, response);
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		doHandle(request, response);
	}

	private void doHandle(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		String user_id = request.getParameter("user_id");
		String user_pwd = request.getParameter("user_pwd");

		MemberVO memberVO = new MemberVO();
		memberVO.setId(user_id);
		memberVO.setPwd(user_pwd);
		MemberDAO dao = new MemberDAO();
		boolean result = dao.isExisted(memberVO);

		if (result) {
			HttpSession session = request.getSession();
			session.setAttribute("isLogon", true);
			session.setAttribute("login.id", user_id);
			session.setAttribute("login.pwd", user_pwd);

			out.print("<html><body>");
			out.print("반갑습니다. " + user_id + " 호갱님!!<br>");
			out.print("<a href='show'>회원 정보 보기</a>");
			out.print("</body></html>");
		} else {
			out.print("<html><body>호갱님의 아이디가 아닙니다.");
			out.print("<a href='login3.html'>다시 로그인 하기</a>");
			out.print("</body></html>");
		}
	}

}

 

로그인에 성공했을때 회원 정보 보기 에서 보여줄 ShowMember 을 작성합니다.

 

@WebServlet("/show")
public class ShowMember extends HttpServlet {
	private static final long serialVersionUID = 1L;

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html;charset=utf-8");
		PrintWriter out = response.getWriter();
		String id = "", pwd = "";
		Boolean isLogon = false;
		HttpSession session = request.getSession(false);

		if (session != null) {
			isLogon = (Boolean) session.getAttribute("isLogon");
			if (isLogon == true) {
				id = (String) session.getAttribute("login.id");
				pwd = (String) session.getAttribute("login.pwd");
				out.print("<html><body>");
				out.print("아이디 : " + id + "<br>");
				out.print("비밀번호 : " + pwd + "<br>");
				out.print("</body></html>");
			} else {
				response.sendRedirect("login3.html");
			}
		} else {
			response.sendRedirect("login3.html");
		}
	}
}

 

모두 작성한 후 웹 브라우저에서 요청하면 로그인 화면이 출력됩니다.

 

 

회원 ID 와 비밀번호를 입력하고 로그인 버튼을 클릭합니다.

 

 

로그인에 성공했으면 회원 정보 보기를 클릭하여 회원 정보를 확인합니다.

 

 

로그인에 실패하면 아쉽지만.. 다음 기회에..

 

 

다른 아이디로 로그인 했다가 다시 /show 로 요청을 해도 세션을 삭제 하지 않았으므로 저장된 회원 정보가 출력됩니다.

 

 

 

여기까지 임미다.

728x90