#다중접속금지,#이중로그인금지#세션공유#아이디공유#이중접속#다중접속
로드밸런싱, 이중화, 메모리 세션만으로 다중 로그인 체크가 어려울 경우, 테이블에 사용자 세션정보를 등록해 체크하는 방법
컬럼 | 타입 | Null | default | 내용 |
---|---|---|---|---|
USER_ID | VARCHAR2(50) | PK | 사용자ID | |
SESSION_ID | VARCHAR2(128) | N | 세션ID | |
ON_YN | CHAR(1) | N | 'Y' | 로그온중 여부 |
CHECK_YN | CHAR(1) | N | 'Y' | 이중로그인 체크 적용여부 |
LOGON_IP | VARCHAR2(128) | N | 로그인 IP | |
ST_DT | DATE | N | SYSDATE | 로그인 시간 |
ED_DT | DATE | N | SYSDATE | 로그아웃 시간 |
<listener>
<listener-class>com.emunhi.config.SessionConfig</listener-class>
</listener>
@Component
public class AppContext implements ApplicationContextAware {
private static ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public static ApplicationContext getContext() {
return context;
}
@SuppressWarnings("unchecked")
public static <T> T getInstance(String className) {
return (T)getContext().getBean(className);
}
}
※ 세션아웃(logoutSession)메소드 에서 로그인중일 경우, 해당 세션 파기와 동시에 테이블에서 로그아웃플래그를 설정한다.
public class SessionConfig implements HttpSessionListener, Serializable {
private static final long serialVersionUID = -4971790522293467330L;
@Override
public void sessionCreated(HttpSessionEvent event) {
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
logoutSession(event);
}
/** 세션아웃 */
private void logoutSession(HttpSessionEvent event){
HttpSession session = event.getSession();
SessionLoginVo svo = (SessionLoginVo)session.getAttribute(“세션빈”);
if(svo==null || svo.getUserId()==null) {
// 세션이 없으면 스킵한다.
return;
}
String userId = svo.getUserId();
String sessionId = session.getId();
UserMapper mapper = AppContext.getInstance("userMapper");
Param param = new Param();
param.put("userId", userId);
param.put("sessionId", sessionId);
mapper.updateLogoutSession(param);
}
}
<update id="updateLogoutSession" parameterType="param">
UPDATE LOGIN_SESSION SET
ON_YN = 'N'
,ED_DT = SYSDATE
WHERE CHECK_YN = 'Y' AND USER_ID = #{userId} AND SESSION_ID = #{sessionId}
</update>
※ 로그인 성공시 세션정보를 테이블에 등록한다.
// 세션로그인 등록
Param pm = new Param();
pm.put("userId", userId);
pm.put("sessionId", request.getSession().getId());
pm.put("logonIp", request.getRemoteAddr());
memberLoginDAO.mergeLoginSession(pm);
<!-- 세션등록 -->
<update id="mergeLoginSession" parameterType="param">
MERGE INTO LOGIN_SESSION A
USING (SELECT #{userId} AS USER_ID FROM DUAL) B
ON (A.USER_ID = B.USER_ID)
WHEN MATCHED THEN
UPDATE SET
SESSION_ID = #{sessionId}
,ON_YN = 'Y'
,LOGON_IP = #{logonIp}
,ST_DT = SYSDATE
WHEN NOT MATCHED THEN
INSERT (USER_ID, SESSION_ID, LOGON_IP)
VALUES ( #{userId}, #{sessionId}, #{logonIp})
</update>
※ 다중로그인 체크는 현재 나의 세션에 대해 인터셉터등에서 상시 체크해 타세션에서 로그인 중인가 확인
※ 인터셉터에서 로그인 세션에 대해 다음을 실행한다.
UserMapper mapper = AppContext.getInstance("userMapper");
Param user = mapper.getLoginSession(userInfo.getUserId());
if(user == null ||
( "Y".equals(user.get("checkYn")) &&
(
"N".equals(user.get("onYn")) || !user.get("sessionId").equals(request.getSession().getId())
)
)
){
// 현세션에 대한 강제로그아웃
request.getSession().invalidate();
// 정상적인 세션정보가 없으면 로그인페이지로 이동
ModelAndView mav = new ModelAndView();
mav.addObject("message", "이중 로그인으로 로그아웃 처리 되었습니다. (사용중 : " + user.get("logonIp") + ")");
mav.setViewName("/login/alert");
throw new ModelAndViewDefiningException(mav);
}
<!-- 중복로그인 금지 처리 -->
<update id="updateLogoutSession" parameterType="EgovMap">
UPDATE LOGIN_SESSION SET
ON_YN = 'N'
,ED_DT = SYSDATE
WHERE CHECK_YN = 'Y' AND USER_ID = #{userId} AND SESSION_ID = #{sessionId}
</update>
<update id="mergeLoginSession" parameterType="EgovMap">
MERGE INTO LOGIN_SESSION A
USING (SELECT #{userId} AS USER_ID FROM DUAL) B
ON (A.USER_ID = B.USER_ID)
WHEN MATCHED THEN
UPDATE SET
SESSION_ID = #{sessionId}
,ON_YN = 'Y'
,LOGON_IP = #{logonIp}
,ST_DT = SYSDATE
WHEN NOT MATCHED THEN
INSERT (USER_ID, SESSION_ID, LOGON_IP)
VALUES ( #{userId}, #{sessionId}, #{logonIp})
</update>
<select id="isNoLoginSession" parameterType="String" resultType="java.lang.Integer">
SELECT COUNT(1) FROM LOGIN_SESSION
WHERE SESSION_ID = #{sessionId} AND ON_YN = 'Y' AND CHECK_YN = 'Y'
</select>
<select id="getLoginSession" parameterType="String" resultType="EgovMap">
SELECT
USER_ID, SESSION_ID,ON_YN, CHECK_YN, LOGON_IP
FROM LOGIN_SESSION
WHERE USER_ID = #{userId}
</select>