자바(JAVA)/JSP 웹 프로그래밍 공부 (성낙현의 JSP 자바 웹 프로그래밍 참고)

JAVA/JSP 18. 세션(Session) - 세션과 DB를 이용한 로그인 구현, 쿠키 vs 세션

개발학생 2023. 11. 30. 23:32
반응형

세션과 DB를 이용한 로그인 구현 (데이터베이스와 연동, 전에 만든 member 테이블의 회원 정보 활용)

1. 로그인 페이지 작성 - 간단한 로그인 폼

  • LoginForm.jsp 파일 생성
// WebContent/Session/LoginForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html>
<head><title>Session</title></head>
<body>
    <h2>로그인 페이지</h2>
		// 1. (span 태그 전체)
    <span style="color: red; font-size: 1.2em;"> 
        <%= request.getAttribute("LoginErrMsg") == null ?
                "" : request.getAttribute("LoginErrMsg") %>
    </span>
    <%
    if (session.getAttribute("UserId") == null) {    // 2.로그인 상태 확인
        // 로그아웃 상태
    %>
    <script>
		// 3.(function 전체)
    function validateForm(form) {
        if (!form.user_id.value) {
            alert("아이디를 입력하세요.");
            return false;
        }
        if (form.user_pw.value == "") {
            alert("패스워드를 입력하세요.");
            return false;
        }
    }
    </script>
		// 4.(form 태그 전체)
    <form action="LoginProcess.jsp" method="post" name="loginFrm"
        onsubmit="return validateForm(this);">    // 5.
        아이디 : <input type="text" name="user_id" /><br />
        패스워드 : <input type="password" name="user_pw" /><br />
        <input type="submit" value="로그인하기" />
    </form>
    <%
    } else { // 로그인된 상태
    %>
				//6.(아래 코드 2줄)
        <%= session.getAttribute("UserName") %> 회원님, 로그인하셨습니다.<br />
        <a href="Logout.jsp">[로그아웃]</a>
    <%
    }
    %>
</body>
</html>
  1. request 내장 객체 영역에 LoginErrMsg 속성이 있는지 확인하고, 그 내용을 출력 (회원 인증 실패 시 request 영역에 이 속성을 저장한 후 포워드 할 예정)
  2. session 영역에 사용자 아이디(UserId)가 저장되어 있는지 확인: 값이 null이면 사용자 아이디가 저장되지 않은 것이므로 ‘로그아웃 상태’
    → 이 코드의 결과에 따라 ‘로그아웃 상태’라면 3.과 4.가 실행되고, 로그인 상태라면 6.이 실행됨
  3. validateForm(): 자바스크립트로 작성한 유효성 검사 함수로, 아이디와 패스워드 중 빈 값이 있다면 경고창을 띄움
  4. form 태그와 input 태그로 작성한 로그인 폼
  5. 4.의 로그인 폼에서 폼값 전송 시, onsubmit 이벤트 핸들러가 validateForm()을 호출하도록 함
    → 유효성 검사 통과 시, 폼에 입력한 값이 post 방식으로 LoginProcess.jsp에 전송됨 (서버에서 이 값을 받아 로그인 처리를 하는데, 이때 DB 연동이 필요함)
  6. 2.에서 session 영역에 사용자 아이디가 저장되어 있다고 판정되면(=로그인 상태라면) 실행됨
    → 로그인한 사용자의 이름, 로그아웃 버튼을 보여 줌

 

2. DB 연동

  • 데이터를 주고받기 위한 DTO 클래스, 테이블에 접근하기 위한 DAO 클래스 생성
DTO
(Data Transfer Object)
= VO(Value Object, 값 객체)
계층 사이에서 데이터를 교환하기 위해 생성하는 객체 별 다른 로직 없이,
속성(멤버 변수)과 그 속성에 접근하기 위한 Getter/Setter 메소드만 갖춤
DAO
(Data Access Objcet)
데이터베이스의 데이터에 접근하기 위한 객체 (JDBC를 통해 구현) 하나의 테이블에서 수행할 수 있는 CRUD(Creste, Read, Update, Delete) 작업을 전담함

 

1) 회원 정보용 DTO 객체 준비

  • 테이블 당 1개이고, 테이블의 컬럼과 동일한 멤버 변수를 가짐
  • Java Resources/src에서 마우스 우클릭 → [New] → [Class] → ‘membership’ 패키지 및 MemberDTO.java 파일 생성
// Java Resources/src/membership/MemberDTO.java

package membership;

public class MemberDTO {
    // 멤버 변수 선언
    private String id;
    private String pass;
    private String name;
    private String regidate;

    // 멤버 변수별 게터와 세터
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getRegidate() {
        return regidate;
    }
    public void setRegidate(String regidate) {
        this.regidate = regidate;
    }
}

 

2) 회원 정보 테이블용 DAO 객체 준비

  • DB에 연결한 후, CRUD에 해당하는 SQL 쿼리문을 실행하고, 그 결과를 DTO 객체에 담아 반환
// Java Resources/src/membership/MemberDAO.java

package membership;

import common.JDBConnect;

public class MemberDAO extends JDBConnect {    //1.
    // 명시한 데이터베이스로의 연결이 완료된 MemberDAO 객체를 생성합니다.
    public MemberDAO(String drv, String url, String id, String pw) {
        super(drv, url, id, pw);    //2.
    }

    // 명시한 아이디/패스워드와 일치하는 회원 정보를 반환합니다.
    public MemberDTO getMemberDTO(String uid, String upass) {    //3.
				//4.(아래 코드 2줄)
        MemberDTO dto = new MemberDTO();  // 회원 정보 DTO 객체 생성
        String query = "SELECT * FROM member WHERE id=? AND pass=?";  // 쿼리문 템플릿

        try {    //5.
            // 쿼리 실행
            psmt = con.prepareStatement(query); //6.(동적 쿼리문 준비)
						//7.(아래 코드 2줄)
            psmt.setString(1, uid);    // 쿼리문의 첫 번째 인파라미터에 값 설정
            psmt.setString(2, upass);  // 쿼리문의 두 번째 인파라미터에 값 설정
            rs = psmt.executeQuery();  //8.(쿼리문 실행)

            // 결과 처리
            if (rs.next()) {    //9.
                // 쿼리 결과로 얻은 회원 정보를 DTO 객체에 저장
								//10.(아래 코드 4줄)
                dto.setId(rs.getString("id"));
                dto.setPass(rs.getString("pass"));
                dto.setName(rs.getString(3));
                dto.setRegidate(rs.getString(4));
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }

        return dto;  //11.(DTO 객체 반환)
    }
}
  1. MemberDAO가 상속한 JDBConnect는 ‘데이터베이스’ 파트에서 만들었던 클래스
    : JDBC 연결 관리와 쿼리문 작성 등의 기능 제공 (DB 연결 시 필수)
  2. 부모인 JDBConnect 클래스의 생성자 중 매개변수 4개짜리를 호출함.
    super()는 부모 클래스의 생성자를 뜻하는데, 이 생성자가 호출되면 DB 연결 완료
  3. getMemberDTO() 메소드: 매개변수로 받은 아이디/패스워드와 일치하는 회원을 찾아 MemberDTO 형태로 반환
  4. DTO 객체와 쿼리문 템플릿 준비
    (아이디와 패스워드가 일치하는 회원 찾음 - 인파라미터인 id=?, pass=?의 값은 7.에서 설정)
  5. try/catch문으로 JDBC 프로그래밍에 기본적으로 필요한 예외처리를 함
  6. 쿼리문 템플릿 완성&실행 시작 단계
    → 인파라미터가 있는 동적 쿼리문을 실행하기 위한, PreparedStatement 객체 생성
         (con은 JDBConnect에서 정의한 멤버 변수로, DB와의 연결 객체)
  7. 쿼리문 템플릿에 ?로 처리된 인파라미터의 값 설정
    → setString() 메소드로, 인덱스 1에 아이디(uid) 설정 & 인덱스 2에 패스워드(upass) 설정
  8. 완성된 쿼리문 실행 (결과 레코드는 ResultSet 객체에 담겨 반환됨)
  9. 결과 레코드에 담긴 dto 객체 채우기의 첫 단계
    → next()메소드로 ResultSet 객체에 레코드가 들어 있는지 확인하고,
        아이디와 패스워드가 일치하는 멤버 존재 시 레코드가 담겨 있으므로 true 반환
  10. 레코드의 값들을 getString() 메소드로 가져와서 dto 객체에 저장
    (getString()의 인수로는, 컬럼명과 인덱스[=테이블 정의에서의 컬럼 순서] 둘 다 가능)
  11. 완성된 DTO 객체를 반환

 

3) 로그인 처리 JSP 구현

  • 사용자로부터 받은 폼값(아이디와 패스워드)으로 로그인을 처리할 JSP 파일
    → 폼값은 LoginForm.jsp 파일의 로그인 화면에서 전달받고, DB상의 정보는 DAO를 이용해 가져옴
  • LoginProcess.jsp 파일 생성
// WebContent/Session/LoginProcess.jsp

<%@ page import="membership.MemberDTO"%>
<%@ page import="membership.MemberDAO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
//1.로그인 폼으로부터 받은 아이디와 패스워드
String userId = request.getParameter("user_id"); 
String userPwd = request.getParameter("user_pw");  

//2.web.xml에서 가져온 데이터베이스 연결 정보
String oracleDriver = application.getInitParameter("OracleDriver");
String oracleURL = application.getInitParameter("OracleURL");
String oracleId = application.getInitParameter("OracleId");
String oraclePwd = application.getInitParameter("OraclePwd");

//회원 테이블 DAO를 통해 회원 정보 DTO 획득
MemberDAO dao = new MemberDAO(oracleDriver, oracleURL, oracleId, oraclePwd);    //3.
MemberDTO memberDTO = dao.getMemberDTO(userId, userPwd);    //4.
dao.close();    //5.

// 로그인 성공 여부에 따른 처리
if (memberDTO.getId() != null) {    //6.
    //7.(아래 코드 2줄 - 로그인 성공)
    session.setAttribute("UserId", memberDTO.getId()); 
    session.setAttribute("UserName", memberDTO.getName());
		//8. 
    response.sendRedirect("LoginForm.jsp");
}
else {
    // 로그인 실패
    request.setAttribute("LoginErrMsg", "로그인 오류입니다.");    //9.
    request.getRequestDispatcher("LoginForm.jsp").forward(request, response);    //10.
}
%>
  1. 로그인 폼에서 전송된 아이디와 패스워드를, request 내장 객체를 통해 받아 둠
    → 로그인 실패 시, 어떤 오류가 발생했는지를 화면에 출력
    → 아이디와 패스워드에 해당하는 회원이 데이터베이스에 존재하면 로그인 성공,
         존재하지 않으면 로그인 실패 (DB에 연결해야 확인 가능)
  2. 데이터베이스 연결 정보는 web.xml에 컨텍스트 초기화 매개변수로 저장해뒀으니,
    application 내장 객체를 통해 가져옴
  3. web.xml에서 가져온 데이터베이스 연결 정보를 건네서,
    MemberDAO 객체 생성 (이 과정에서 오라클 데이터베이스 접속)
  4. 사용자가 입력한 아이디와 패스워드를 인수로 getMemberDTO()를 호출
    → 아이디와 패스워드 일치 시 해당 회원의 정보가 저장된 DTO 객체 반환
  5. 데이터베이스 작업이 다 끝났으므로, 데이터베이스 연결 해제
  6. DTO 객체에 아이디가 담겨 있다면 로그인 성공
  7. 로그인 성공 시 이 session 영역에 아이디와 이름을 저장한 후
  8. 로그인 페이지로 이동 (7.에서 이어짐)
  9. 로그인 실패 시, 이 request 영역에 오류 메시지를 저장함
    [request 영역에 저장된 속성값은 포워드된 페이지까지 공유됨]
  10. 로그인 페이지로 포워드함 (9.에서 이어짐)

 

4) 동작 확인

  • LoginForm.jsp를 [Run On Server]로 실행하고, ‘아이디’와 ‘패스워드’에 일부러 잘못된 값을 입력한 후 [로그인하기] 버튼 클릭

 

  • 로그인에 실패했으므로, LoginProcess.jsp에서 LoginForm.jsp로 포워드됨
    → 주소표시줄에는 LoginProcess.jsp가 표시되지만 화면에는 LoginForm.jsp의 내용이 출력됨
        (request 영역에 저장된 “로그인 오류입니다.” 출력됨)

 

  • ‘아이디’, ‘패스워드’에, member 테이블에 입력했던 데이터인 ‘hello’, ‘1234’를 각각 입력 후 [로그인하기] 버튼 클릭

 

3. 로그아웃 처리

  • session 영역에 저장된 로그인 관련 속성을 모두 지워주기만 하면 됨

1) 프로젝트의 [WebContent] → [Session]에서 Logout.jsp 파일 생성 후 코드 작성

// WebContent/Session/Logout.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
// 방법 1: 회원인증정보 속성 삭제 
session.removeAttribute("UserId");
session.removeAttribute("UserName");

// 방법 2: 모든 속성 한꺼번에 삭제 
session.invalidate();

// 속성 삭제 후 페이지 이동 
response.sendRedirect("LoginForm.jsp");
%>

방법 1: removeAttribute()가 인수로 지정한 특정 속성을 선택해서 삭제하는 메소드

방법 2: invalidate()가 session 영역의 모든 속성을 한꺼번에 삭제하는 메소드 (세션 자체를 무효화 함 - 세션 정보를 더 이상 유지할 필요 없으므로 부담이 줄어듬)

속성 삭제 후 페이지 이동: 로그아웃 후 로그인 페이지로 이동

  • 아이디, 패스워드에 ‘hello’, ‘1234’를 각각 입력 후 [로그인하기] 버튼 클릭 후 로그인에 성공한 상태에서,
    [로그아웃] 버튼을 클릭
    → 처음의 로그인 페이지(LoginForm.jsp)로 이동

 

4. 공통 링크 추가

  • 페이지 사이의 이동을 좀 더 편하게 하기 위해, 로그인 페이지 상단에 공통 링크 추가

 

1) 프로젝트의 [WebContent] → [Common]에 Link.jsp 파일 생성

// WebContent/Common/Link.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" 
    pageEncoding="UTF-8"%>
<table border="1" width="90%">
	<tr>
		<td align="center">
		<!-- 로그인 여부에 따른 메뉴 변화 -->
		<% if (session.getAttribute("UserId") == null) { %>
			<a href="../Session/LoginForm.jsp">로그인</a>    <!-- 1. -->
		<% } else { %>
			<a href="../Session/Logout.jsp">로그아웃</a>    <!-- 2. -->
		<% } %>
			<!-- 회원제 게시판 프로젝트 진행 시 사용할 공통 링크 -->
			&nbsp;&nbsp;&nbsp; <!-- 메뉴 사이의 공백(space) 확보용 특수 문자 -->
			<a href="../Board/List.jsp">게시판(페이징 X)</a>    <!-- 3. -->
			&nbsp;&nbsp;&nbsp;
			<a href="..PagingBoard/List.jsp">게시판(페이징 O)</a>    <!-- 4. -->
		</td>
	</tr>
</table>
  1. 로그아웃 상태면 [로그인] 링크를 출력
  2. 로그인 상태면 [로그아웃] 링크를 출력
  3. 페이징 X 게시판으로 갈 링크
  4. 페이징 O 게시판으로 갈 링크

 

2) 1)의 공통 링크를 로그인 폼(LoginForm.jsp) 상단에 추가

  • LoginForm.jsp 파일 코드 추가
// WebContent/Session/LoginForm.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html>
<head><title>Session</title></head>
<body>
	<jsp:include page="../Common/Link.jsp" />    <!--공통 링크 추가 -->
    <h2>로그인 페이지</h2>
    ...생략...
</body>
</html>

 

3) 동작 확인

  • LoginForm.jsp 파일을 [Run On Server]로 실행
    → ‘로그인 페이지’ 글자 위에 공통 링크가 생겼고, 공통 링크 중 ‘로그인’은 로그인을 했을 때 ‘로그아웃’으로 바뀜

 

쿠키 vs 세션

  • 로그인은 쿠키보다는 세션을 이용해 구현하는 것이 좋음
  쿠키 세션
저장 위치/형식 클라이언트 PC에 text로 저장됨 웹 서버에 Object 타입으로 저장됨
보안 클라이언트에 저장되어 보안에 취약 서버에 저장되므로 보안에 안전함
자원/속도 서버 자원 사용 X/속도가 세션보다 빠름 서버 자원 사용 O/속도가 쿠키보다 느림
용량 용량 제한 O 용량 제한 X (서버가 허용하는 한)
유지 시간 쿠키 생성 시 설정 (설정 된 시간 경과 시 무조건 삭제됨) 서버의 web.xml에서 설정
(설정 된 시간 경과 시에도 동작이 있으면 삭제되지 않고 유지됨)    

 

 

반응형