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
xxxxxxxxxx
package 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 |