웹기반 애플리케이션

JSP_Session을 이용한 로그인/로그아웃 만들기

비비펄 2023. 3. 17. 20:13

📕일단 VO(Value Ojbect)를 먼저 만든다

package kr.or.ddit.vo;

import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * JavaBean 규약
 * ValueObject, DataTransferObject, Model, Bean
 * ex) MemberVO, MemberDTO, MemberModel, MemberBean 
 * 
 * 1. 값을 저장할 속성(property) 정의
 * 2. 캡슐화
 * 3. 캡슐화된 데이터에 접근할 인터페이스 제공(getter/setter)
 * 		get[set]프로퍼티명에서 첫문자만 대문자, camel case 적용
 * 4. 상태 비교 메소드 제공 hashcode equals()
 * 5. 상태 확인 메소드 제공 == toString
 * 6. 직렬화
 * 
 * 회원관리와 인증시스템을 위한 Domain Layer
 */

public class MemberVO implements Serializable{
	private String memId;
    //password의 노출을 막기위해 transient와 JsonIgnore를 이용한다
	@JsonIgnore
	private transient String memPass;
	private String memName;
	public String getMemId() {
		return memId;
	}
    //getter와 setter만들기
	public void setMemId(String memId) {
		this.memId = memId;
	}
	public String getMemPass() {
		return memPass;
	}
	public void setMemPass(String memPass) {
		this.memPass = memPass;
	}
	public String getMemName() {
		return memName;
	}
	public void setMemName(String memName) {
		this.memName = memName;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((memId == null) ? 0 : memId.hashCode());
		return result;
	}
    //hashCode and equals를 통해 memId의 중복체크
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		MemberVO other = (MemberVO) obj;
		if (memId == null) {
			if (other.memId != null)
				return false;
		} else if (!memId.equals(other.memId))
			return false;
		return true;
	}
    //toString에서도 password노출을 막기위해 password는 체크하지않는다
	@Override
	public String toString() {
		return "MemberVO [memId=" + memId + ", memName=" + memName + "]";
	}
	
}

📕그다음 DAO와 Service를 만들어야하지만 일단은 구현하지 않아도 사용할 수 있도록 Interface부터 구현한다.

✔ServiceInterface

package kr.or.ddit.member.service;

import kr.or.ddit.member.exception.AuthenticateException;
import kr.or.ddit.vo.MemberVO;

public interface AuthenticateService {
	/**
	 * 아이디와 비밀번호 기반의 인증 처리
	 * @param input
	 * @return 인증에 성공한 경우, 해당 사용자의 정보를 가진 VO
	 * @throws AuthenticateException 인증 실패
	 */
	public MemberVO authenticate(MemberVO input) throws AuthenticateException;
}

✔DAOInterface

package kr.or.ddit.member.dao;

import kr.or.ddit.vo.MemberVO;

/**
 * 회원관리와 인증시스템을 위한 Persistence Layer
 */
public interface MemberDAO {
	/**
	 * PK로 회원 한명의 정보 조회
	 * @param memId
	 * @return 존재하지 않는 경우, null반환.
	 */
	public MemberVO selectMemberForAuth(String memId);
}

📕Interface를 Implement한다

✔DAOImpl

package kr.or.ddit.member.dao;

import java.util.LinkedHashMap;
import java.util.Map;

import kr.or.ddit.vo.MemberVO;

public class MemberDAOImpl_InMemory implements MemberDAO {
	
	private Map<String, MemberVO> memberDB;
	
	
	public MemberDAOImpl_InMemory() {
		super();
		memberDB = new LinkedHashMap<>();
		MemberVO a001VO = new MemberVO();
		a001VO.setMemId("a001");
		a001VO.setMemPass("java");
		a001VO.setMemName("김은대");
		memberDB.put("a001", a001VO);
		MemberVO b001VO = new MemberVO();
		b001VO.setMemId("b001");
		b001VO.setMemPass("java");
		b001VO.setMemName("이쁜이");
		memberDB.put("b001", b001VO);
	}


	@Override
	public MemberVO selectMemberForAuth(String memId) {
		
		return memberDB.get(memId);
	}

}

✔serviceImpl

package kr.or.ddit.member.service;


import kr.or.ddit.member.dao.MemberDAO;
import kr.or.ddit.member.dao.MemberDAOImpl_InMemory;
import kr.or.ddit.member.exception.AuthenticateException;
import kr.or.ddit.vo.MemberVO;


public class AuthenticateServiceImpl implements AuthenticateService {
	
	// 의존 객체를 직접 인스턴스화. 결합력 최상.
	private MemberDAO dao = new MemberDAOImpl_InMemory();
	
	@Override
	public MemberVO authenticate(MemberVO input) throws AuthenticateException {
		MemberVO saved = dao.selectMemberForAuth(input.getMemId());
		if(saved!=null) {
			String inputPass = input.getMemPass();
			String savedPass = saved.getMemPass();
			if(savedPass.equals(inputPass)) {
				return saved;
			}
		}
		throw new AuthenticateException(input.getMemId());
	}

}

📕Controller_login

package kr.or.ddit.member.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 org.apache.commons.lang3.StringUtils;

import kr.or.ddit.member.exception.AuthenticateException;
import kr.or.ddit.member.service.AuthenticateService;
import kr.or.ddit.member.service.AuthenticateServiceImpl;
import kr.or.ddit.vo.MemberVO;

/**
 * 1. 둘중의 하나 혹은 모든 파라미터가 누락되면, 400 에러 전송
 * 2. 인증 실패라면, loginForm으로 이동("로그인에 실패했음" 공유, attribute name : message)
 *      -> loginForm에서 "로그인에 실패했음" 이라는 메시지를 swal로 출력. 
 * 3. 인증 성공시, 웰컴 페이지로 이동. (인증에 성공한 사용자의 VO를 공유, attribute name : authMember)
 *      -> "김은대님 로그인" 메시지 출력.
 */
@WebServlet("/login/loginProccess")
public class LoginProcessControllerServlet extends HttpServlet {
	private AuthenticateService service = new AuthenticateServiceImpl();
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		//세션을 통한 공격을 막기위한 방지코드
        HttpSession session = req.getSession();
		if(session.isNew()) {
			resp.sendError(400);
			return;
		}
        //폼에서 Parameter값을 받아온다
		req.setCharacterEncoding("utf-8");
		String memId = req.getParameter("memId");
		String memPass = req.getParameter("memPass");
		
        //VO생성 뒤 파라미터 값들을 넣어준다
		MemberVO input = new MemberVO();
		input.setMemId(memId);
		input.setMemPass(memPass);
		
		boolean valid = validate(input);
		String viewName = null;
		if(valid) {
			try {
				MemberVO saved = service.authenticate(input);
				
				session.setAttribute("authMember", saved);
				viewName= "/";
				
				
			}catch(AuthenticateException e) {
				String message = "로그인 실패";
				session.setAttribute("message", message);
				viewName = "/login/loginForm.jsp";
				
			}
			
		}else {
			session.setAttribute("message", "필수 파라미터 누락");
		}
		resp.sendRedirect(req.getContextPath() + viewName);
			
	}
	
    //StringUtils를 통한 null방지
	private boolean validate(MemberVO input) {
		boolean valid = true;
		
		if(StringUtils.isBlank(input.getMemId())) {
			valid = false;
		}
		if(StringUtils.isBlank(input.getMemPass())) {
			valid = false;
		}
		return valid;
	}
}

📕Controller_logout

package kr.or.ddit.member.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;

@WebServlet("/login/logout")
public class LogoutCotrollerServlet extends HttpServlet{
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		HttpSession session = req.getSession();
		if(session.isNew()) {
			resp.sendError(400, "유효 세션이 아님.");
			return;
		}
//		session.removeAttribute("authMember");
		session.invalidate();//더이상 세션을 사용할 수 없는 상태로 만들어줌
		
		resp.sendRedirect(req.getContextPath()+"/");
	}
}

📕view_form

<%@page import="org.apache.commons.lang3.StringUtils"%>
<%@ 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>
<jsp:include page="/includee/preScript.jsp"/>
<%
	String message = (String) session.getAttribute("message");
session.removeAttribute("message"); // flash attribute
	if(StringUtils.isNotBlank(message)){
		%>
<script>
alert("<%=message%>");
// Swal.fire({
// 	  icon: 'error',
// 	  title: 'Oops...',
<%-- 	  text: '<%=message%>', --%>
// 	})
</script>		
		<%
	}
%>
</head>
<body>
<form action="<%=request.getContextPath() %>/login/loginProccess" method="post">
	<ul>
		<li>아이디 : <input type="text" name="memId" /></li>
		<li>비밀번호 : <input type="password" name="memPass" /></li>
		<li>
			<input type="submit" value="로그인"/>
		</li>
	</ul>
</form>


<jsp:include page="/includee/postScript.jsp"/>
</body>
</html>

'웹기반 애플리케이션' 카테고리의 다른 글

JSP📃_Scope(영역)  (0) 2023.03.17
JSP📃_copy  (0) 2023.03.16
JSP📃_Application  (0) 2023.03.16
JSP📃_JSP 스펙에서 제공되는 기본객체  (0) 2023.03.16
JSP📃_Buffer  (0) 2023.03.16