JSP 중복 로그인 (세션 바인딩 리스너)
중복 로그인을 회피하기 위해 HttpSessionBindingListener 인터페이스를 구현했습니다
Session Listener에서 두 가지를 비교해서 설명 해 드리면
HttpSessionListener는 세션의 생성과 세션이 해제 되는 이벤트에 맞게 리스너를 호출 할 수 있습니다.
HttpSessionBindingListener는 세션바인딩리스너 인터페이스를 구현한 세션에 바인딩 시키거나 언바인딩 되는 이벤트에 맞게 리스너를 호출 할 수 있습니다.
(세션의 속성을 추가 , 제거 를 뜻함)
1. 흐름
1.1
header.jsp 에서 로그인 시도 - ajax를 통해 서블릿으로 아이디와 비밀번호 및 아이디 저장 체크 유무 전송
1.2
FrontController.java 에서 url-pattern 및 분기를 통해 해당 Command로 이동
1.3
LoginCommand.java 에서 아이디와 비밀번호가 알맞을 경우, setSession을 통해 HashTable에 저장합니다.
세션바인딩 리스너는 setSession 메소드가 호출 했을 경우 valueBound가 실행 되며 ,
session.invalidate(); 와 같이 세션의 속성을 제거 했을 때 valueUnBound가 실행됩니다.
그리고 세션바인딩 리스너 인터페이스를 구현한 클래스는 싱글톤 패턴을 통해 효율적으로 관리됩니다.
이때 유저의 정보를 담고 있는 HashTable은 static으로 지정을 해 스태틱 메모리 영역에 저장을 합니다.
이는 공유하기 위해 요기다가 저장 하는 겁니당
1.4
이후 header.jsp에서 로그아웃을 하면 서블릿을 통해 해당 Command(Logout)로 이동하여 session.invalidate(); 를
실행합니다. 이 때 세션바인딩 리스너에서 valueUnBound가 실행되며 HashTable에서 해당하는 아이디가 제거됩니다.
1.5
중복아이디를 판단하는 메소드는 간단합니다. 세션 바인딩 리스너에서 isUsing 메소드를 통해서 현재 아이디가 HashTable
에 담겨 있다면 true를 반환하고, 없다면 false를 반환합니다.
LoginCommand에서 SessionListener.getInstance().isUsing(userId) 를 조건문으로 두어 중복로그인 인지 판별합
니다.
header.jsp
function loginCheck(){ var userId = $("#userId").val().trim(); var userPassword = $("#userPassword").val().trim(); var saveId = $("#saveId").is(":checked") console.log("$saveId는 바로 ! = " , saveId) if(userId == 0 || userPassword == 0){ $("#login-help").text("아이디 혹은 비밀번호를 입력해 주시길 바랍니다."); $("#login-help").addClass("text-danger"); return; } $.ajax({ url : "<%=request.getContextPath()%>/login.do", type : "POST", data : {userId : userId , userPassword : userPassword, saveId : saveId}, success : function(data){ if(data == "true"){ location.reload(); console.log("여긴 오지"); } else if(data == "false"){ $("#login-help").text("아이디 혹은 비밀번호가 알맞지 않습니다."); $("#login-help").addClass("text-danger"); } else if(data == "already"){ $("#login-help").text("이미 아이디가 접속중입니다!"); $("#login-help").addClass("text-danger"); } else if(data == "oldPwdChangeOrLater"){ location.href ="<%=request.getContextPath()%>/sign/OldPwdChangeOrLater.do?userId="+userId; alert("비밀번호 변경한지 90일이 지났습니다. 변경페이지로 이동합니다."); } } }); }
LoginCommand.java
xpackage com.brw.command.user;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import com.brw.command.Command;import com.brw.dao.DAO;import com.brw.dto.UserDTO;import com.brw.listener.SessionListener;/** * 작성자 : 김은찬 * 내용 : 로그인 시 아이디 저장 및 세션에 유저 정보 저장 */public class LoginCommand implements Command { public void execute(HttpServletRequest request, HttpServletResponse response) { // TODO Auto-generated method stub String userId = request.getParameter("userId"); String userPassword = request.getParameter("userPassword"); DAO dao = DAO.getInstance(); int result = dao.loginCheck(userId , userPassword); try { PrintWriter out = response.getWriter(); // 로그인 성공 ! if(result == 1) { // 로그인 성공 했을 경우 쿠키 저장 String saveId = request.getParameter("saveId"); // (아이디 저장 체크시)쿠키 생성 , 쿠키의 생성은 server , 보관은 클라 if(saveId.equals("true")) { Cookie c = new Cookie("saveId", userId); // 쿠키 유효시간 1일 , c.setMaxAge(24*60*60); c.setPath("/brw"); response.addCookie(c); } // (아이디 저장 체크 X) , 저장된 쿠키 삭제 else { Cookie c = new Cookie("saveId", userId); c.setMaxAge(0); c.setPath("/brw"); response.addCookie(c); } HttpSession session = request.getSession(true); // 이미 접속한 아이디인지 체크 // 현재 접속자들 보여주기 SessionListener.getInstance().printloginUsers(); if(SessionListener.getInstance().isUsing(userId)) { System.out.println("이미 아이디가 접속중 입니다."); out.append("already"); return; } // 접속 하고자 하는 아이디의 세션을 담는다 UserDTO userDTO = new UserDTO(); userDTO = dao.selectOneUser(userId); session.setMaxInactiveInterval(60*10); session.setAttribute("user", userDTO); SessionListener.getInstance().setSession(session, userId); int changeDate = dao.checkDate(userId); System.out.println("$loginCommand() changeDate = "+changeDate); if(changeDate > 90) out.append("oldPwdChangeOrLater"); else out.append("true"); } // 로그인 실패 ! else out.append("false"); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
SessionListener.java
xxxxxxxxxxpackage com.brw.listener;import java.util.Collection;import java.util.Enumeration;import java.util.Hashtable;import javax.servlet.http.HttpSession;import javax.servlet.http.HttpSessionBindingEvent;import javax.servlet.http.HttpSessionBindingListener;import com.brw.dto.UserDTO;/** * 작성자 : 김은찬 * 내용 : 중복 로그인을 방지하기 위한 세션 리스너 */public class SessionListener implements HttpSessionBindingListener{ // 싱글톤 객체를 담을 변수 private static SessionListener sessionListener = null; // 로그인한 접속자를 저장한 HashTable (데이터를 해시하여 테이블 내의 주소를 계산하고 데이터를 담는 것 , 해시함수 알고리즘은 나눗셈 법. 자릿수 접기 등등) private static Hashtable loginUsers = new Hashtable(); // 싱글톤 처리 public static synchronized SessionListener getInstance() { if(sessionListener == null) { sessionListener = new SessionListener(); } return sessionListener; } // 세션이 연결시 호출 (해시테이블에 접속자 저장) public void valueBound(HttpSessionBindingEvent event) { // TODO Auto-generated method stub loginUsers.put(event.getSession(), event.getName()); System.out.println(event.getName() + " 로그인 완료"); System.out.println("현재 접속자 수 : " + getUserCount()); } // 세션이 끊겼을시 호출 public void valueUnbound(HttpSessionBindingEvent event) { // TODO Auto-generated method stub loginUsers.remove(event.getSession()); System.out.println(event.getName() + " 로그아웃 완료"); System.out.println("현재 접속자 수 : " + getUserCount()); } // 입력받은 아이디를 해시테이블에서 삭제 public void removeSession(String userId) { Enumeration e = loginUsers.keys(); HttpSession session = null; while(e.hasMoreElements()){ session = (HttpSession)e.nextElement(); if(loginUsers.get(session).equals(userId)){ //세션이 invalidate될때 HttpSessionBindingListener를 //구현하는 클레스의 valueUnbound()함수가 호출된다. session.invalidate(); } } } /* * 해당 아이디의 동시 사용을 막기위해서 * 이미 사용중인 아이디인지를 확인한다. */ public boolean isUsing(String userId){ return loginUsers.containsValue(userId); } /* * 로그인을 완료한 사용자의 아이디를 세션에 저장하는 메소드 */ public void setSession(HttpSession session, String userId){ //이순간에 Session Binding이벤트가 일어나는 시점 //name값으로 userId, value값으로 자기자신(HttpSessionBindingListener를 구현하는 Object) session.setAttribute(userId, this);//login에 자기자신을 집어넣는다. } /* * 입력받은 세션Object로 아이디를 리턴한다. * @param session : 접속한 사용자의 session Object * @return String : 접속자 아이디 */ public String getUserID(HttpSession session){ return (String)loginUsers.get(session); } /* * 현재 접속한 총 사용자 수 * @return int 현재 접속자 수 */ public int getUserCount(){ return loginUsers.size(); } /* * 현재 접속중인 모든 사용자 아이디를 출력 * @return void */ public void printloginUsers(){ Enumeration e = loginUsers.keys(); HttpSession session = null; System.out.println("==========================================="); int i = 0; while(e.hasMoreElements()){ session = (HttpSession)e.nextElement(); System.out.println((++i) + ". 접속자 : " + loginUsers.get(session)); } System.out.println("==========================================="); } /* * 현재 접속중인 모든 사용자리스트를 리턴 * @return list */ public Collection getUsers(){ Collection collection = loginUsers.values(); return collection; }}
'Spring' 카테고리의 다른 글
| DI 설정 방법 - xml (0) | 2018.09.06 |
|---|---|
| DI 설정 방법 - JAVA (0) | 2018.09.06 |
| DI 설정 방법 - Java & xml 같이 사용 (0) | 2018.09.06 |
| Spring 한글 깨짐 현상 (0) | 2018.07.17 |




