컴퓨터활용/자바

중복 로그인 방지 로직

멜번초이 2012. 4. 22. 23:33

중복 로그인을 체크하는 로직을 구현하는 미션이 프로젝트 마지막 단계에 주어졌다. 중복 로그인했을 때 먼저 로그인한 사용자가 세션 아웃 되는 것을 표준으로 정하였다. 이 때 최종 접속자의 IP와 로그인시각을 안내 받아야 한다는 전제조건이 있다.


스프링에서 제공하여 security 기능을 이용하여 구현해 보고자 했으나 생각대로 잘 되지 않았다. 스프링 설정으로 중복 로그인을 체크할 수는 있었으나 최종 접속자의 IP와 접속시각을 보여주고자 하는 곳에서 난관을 만났다.  세션이 invalid 되었기 때문에 세션아이디를 비롯한 사용자아이디, 접속IP등 세션에 보관되어 있는 정보가 싸그리 사라져 버린 상황이었기 때문이다.


그래서 결국 로그인 히스토리를 보관하고 있는 테이블에서 정보를 추출하여 중복로그인을 체크하도록 구현해 보았다. 사라지지 않은 확실한 정보는 IP이기 때문이다. 먼저 사용자의 IP로 사용자아이디를 구해내고 이 사용자아이디의 최종접속기록을 조회한다. 접속 IP가 사용자의 것과 동일하면 문제 될 것이 없으나 IP가 다르다면 다른 사용자가 로그인을 한 상황이므로 사용자는 세션아웃되어야 한다.  


로그인을 할 때 사용자아이디, 로그인시각, IP등을 보관해 두는 테이블이 TB_LOG_HIST 이다. 성능을 위해서 이 테이블에 INDEX 를 두개를 만들어야 한다.  USER_ID ASC, LOG_DDTT DESC 로 IX_TB_LOG_HIST_01를 만든다. 또한 IP ASC, LOG_DDTT DESC로 IX_TB_LOG_HIST_02를 작성한다. 


-- 세션아이디로 사용자를 구해 그 사용자가 최종 로그인한 시각을 구함

SELECT /*+ INDEX(TB_LOG_HIST IX_TB_LOG_HIST_01) */

       USER_ID

       , IP 

       , TO_CHAR(TO_DATE(SUBSTR(LOG_DDTT, 1,14), 'YYYYMMDDHH24MISS'), 'YYYY-MM-DD HH24:MI:SS') LAST_LOG_IN_DDTT

       , TO_CHAR(sysdate - 30*1/24/60, 'YYYY-MM-DD HH24:MI:SS') BF_30_MINUTE  -- 30분전시각

    FROM TB_LOG_HIST

    WHERE IP NOT IN ('127.0.0.1', '0:0:0:0:0:0:0:1') -- 로컬IP는 제외

    AND   ROWNUM = 1

    AND   USER_ID =  

                  ( SELECT /*+ INDEX(TB_LOG_HIST IX_TB_LOG_HIST_02) */  USER_ID

                    FROM TB_LOG_HIST

                    WHERE IP = :ip AND LOG_TYPE = '03'  -- 03:로그인

                    AND ROWNUM = 1 )


조회한 IP 와 사용자를 이용하여 중복 체크 루틴을 태우는 것은 대충 아래와 같이 구현한다.


// 세션 체크 대상인 프로그램인 경우는 세션에서 사용자 정보 체크

if (SecurityUtils.getSignedUser() == null) {

    throw new SessionTimeoutException("\n세션이 종료되었습니다. \n\n다시 접속해 주시기 바랍니다");

}

else {

    // 동일유저로 다른 단말(IP)에서 로그인 된 경우 세션을 종료한다.

       

    // 개발자 PC 에서 실행된 경우 예외처리

    if( ! "127.0.0.1".equals(request.getRemoteAddr()) &&             // XP 에서 로컬아이피

        ! "0:0:0:0:0:0:0:1".equals(request.getRemoteAddr())) {            // win7 에서 로컬아이피

 

         SearchParameters searchParameters = new SearchParameters();

         searchParameters.put("ip", request.getRemoteAddr());

              

         RecordSet rs = logHistDao.selectLastLoginInfo(searchParameters);

         if( rs.getRowCount() == 0) {

             throw new SessionTimeoutException("\n세션이 종료되었습니다.\n\n다시 접속해 주시기 바랍니다");

         }

         else {

             Record  rd = rs.get(0);

              

             if( !request.getRemoteAddr().equals(rd.getString("ip")) ) {

                 throw new SessionTimeoutException("\n\n다른 단말에서 로그인되어 사용을 종료합니다."

                      +"\n\n접속IP:"+rd.getString("ip")+"  접속시간:"+rd.getString("lastLogInDdtt"));

             }

        }

    }

}