Post
EN

Spring framework 중복로그인 체크 관련

Spirng 3.0 에서 적용하였다.

spring security 미적용.

참조 : http://www.oraclejavanew.kr/bbs/board.php?bo_table=LecServletJSP&wr_id=204

위 내용을 참조하여 해당되는 클래스를 구현하였다.

출처 : http://hajubal.blogspot.kr/2013/04/servlet-listener.html

▶ javax.servlet.http.HttpSessionBindingListener HttpSession에 대하여 클라이언트 세션정보에 대한 바인딩이 이루어졌을 경우 감지되는 리스너이며 이번 예제에서 사용될 리스너이기도 한다. HttpSessionBindingEvent객체를 실제 구현클래스로 넘겨주게 된다. 위의 리스너 모두 servlet2.3부터 나오기 시작했으며, 현재 사용되는 거의 모든 엔진들이 지원을 하고 있으므로 사용하는데 대하여 무리가 없으리라 본다. 자, 그러면 이제 예제를 하나 만들어보도록 하자. 놀새가 만들어볼 예제는 HttpSessionBindingListener라고 하였다. 이것을 왜 만들었는지부터 살펴보아야 하지 않을까? 이유는 간단했다. 예전 프로젝트의 경우 클라이언트 접속에 대하여 사용자정보를 세션에 담도록 하고 있는 그 담긴 세션에 대하여 정보를 얻어내려 하였다. 사용자 정보 및 저장된 세션에 대하여 collection에 현재 이용중인 사용자 및 그 사용자 정보들을 어드민 관리차원에서 보고 싶었던 것이다. 각종 리스너들을 이용한다면 그러한 정보들을 쉽게 얻어낼 수 있는 특징을 가지고 있었다.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

package mngwserc.com.uat.uia.web;

import java.util.Enumeration;

import java.util.Hashtable;

import java.util.Iterator;

import java.util.Map;

import javax.servlet.http.HttpSession;

import javax.servlet.http.HttpSessionBindingEvent;

import javax.servlet.http.HttpSessionBindingListener;

import org.springframework.stereotype.Component;

@Component(“DuplicateLoginPrevent”)

public class DuplicateLoginPrevent implements HttpSessionBindingListener{

    / 로그인 유저 관련 해쉬 테이블 /

    private static Hashtable userList = new Hashtable();

       /**

        * 해당 아이디가 로그인 되어있는지

        * @param sessionID

        * @return

        */

       public boolean isLogin(String sessionID){

                     boolean isLogin = false;

                     Enumeration e = userList.keys();

                     String key = ””;

                     while(e.hasMoreElements()){

                                  key = (String)e.nextElement();

                                  if(sessionID.equals(key)){

                                               isLogin = true;

                                  }

                     }

                     return isLogin;

       }

       /**

        * 해당 아이디가 사용중인지

        * @param userID

        * @return

        */

       public boolean isUsing(String userID, HttpSession session){

                     boolean isUsing = false;

                     Enumeration e = userList.keys();

                     String key = ””;

                     while(e.hasMoreElements()){

                          key = (String)e.nextElement();

                          if(!key.equals(session.getId()) && userID.equals(userList.get(key))){

                              isUsing = true;

                          }

                     }

                     System.out.println(“is Using ” + isUsing);

                     return isUsing;

       }

       /**

        * 세션 생성 , user 저장

        * @param session

        * @param userID

        */

       public void setSession(HttpSession session, String userID){

                       userList.put(session.getId(), userID);

                     //session.setAttribute(“login”, this.getInstance());

                    System.out.println(“user list ” + userList);

       }

       /**

        * 세션 생성될때

        */

        public void valueBound(HttpSessionBindingEvent event) {

            // TODO Auto-generated method stub

        }

        /**

         * 세션 끊길 때

         */

        public void valueUnbound(HttpSessionBindingEvent event) {

            // TODO Auto-generated method stub

            userList.remove(event.getSession().getId());

        }

        /**

         * 중복 로그인시 이전 로그인 세션 날리기

         * @param session

         */

        public void removeLoginInfo(HttpSession session, String userID){

            Iterator<Map.Entry<String, String» itr = userList.entrySet().iterator();

            String sessionId = session.getId();

            while(itr.hasNext()){

                Map.Entry<String, String> data = itr.next();

                System.out.println(“data =====> ” + data);

                if(data.getValue().trim().equals(userID)){

                    System.out.println(data);

                    userList.remove(data.getKey());            // 로그인 해지할 사용자 세션 추가 이후 interceptor에서 확인 후 로그 아웃으로 보냄

                    System.out.println(“user list ” + userList);

                    return;

                }

            }

        }

        /**

         * 금지 사용자 목록 가져오기

         * @return

         */

        public Hashtable getUserList(){

            return userList;

        }

}

로그인 컨트롤러를 통해서 상속 받은 뒤 위 클래스를 이용하여 작업하였다.

1

2

3

4

5

@Controller

public class EgovLoginController extends DuplicateLoginPrevent{

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

    /**

                 * 2014.12.31  중복로그인 방지 관련 추가

                 * 관련 로직 설명

                 *

                 *  로그인 된 계정들은 static hashtable 변수에 담아놈

                 *  1. 같은 계정이 있는지 여부 확인 후 없으면 바로 저장.

                 *  2. interceptor를 통해서 해당 변수를 계속적으로 확인.

                 *  3. 저장된 세션,계정아이디 등확인 후 없으면 메시지 노출 후 로그아웃 시킴

                 *

                 */

                    if(super.isUsing(resultVO.getId(), session)){                // 기존 로그인 된 회원이면

                        super.removeLoginInfo(session, resultVO.getId());        // 기존 세션 정보 삭제

                    }

                        super.setSession(session,resultVO.getId());        // 로그인 회원

그리고 나서 부모 메서드를 호출하는 식으로해서 작업을 진행하였다.

이후 인터페이스에서 메뉴 이동시마다 Hashtable에 저장된 세션 아이디 값을 비교하며, 중복로그인 된 회원을 로그아웃 시키도록 하였다.

인터셉터에서 위에서 선언한 것 처럼 component 명을 불러와서 DI를 주입시켰다.

이후 postHandler 쪽에서 확인하도록 하였다.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

public class AuthenticInterceptor extends HandlerInterceptorAdapter {

    private String[] permittedURL;

    private String ENCODE = ”UTF-8”;

    @Resource(name=”DuplicateLoginPrevent”)

    private DuplicateLoginPrevent duplicate;

    …

1

2

3

4

5

6

                // 세션 가져오기

                HttpSession session = request.getSession(false);

                // 로그인 정보

                LoginVO loginVO = (LoginVO) EgovUserDetailsHelper.getAuthenticatedUser();

                // 중복 로그인 방지

                duplicationLoginPrevent(session, loginVO, response);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

    /**

     * 중복 로그인 관련 체크하는 메서드

     * @param session

     * @param loginVO

     * @param response

     * @throws Exception

     */

    public void duplicationLoginPrevent(HttpSession session, LoginVO loginVO, HttpServletResponse response) throws Exception{

        System.out.println(duplicate.getUserList());

        Hashtable loginUsers = duplicate.getUserList();

        Iterator<Map.Entry<String, String» itr = loginUsers.entrySet().iterator();

        // 비교할 세션 아이디

        String compareSessionId = session.getId();

        String loginId = loginVO.getId();

        String compareLoginId =””;

        boolean result = false;    // 결과

            while(itr.hasNext()){

                Map.Entry<String, String> user = itr.next();

                /**

                 *  로그인 중이였는데 다른 단말기에서 로그인하여 로그인을 취소할때.

                 *

                 *  세션아이디가 같은데 접속 계정이 다르면 alert

                 */

                compareLoginId = user.getValue();

                if(compareSessionId.equals(user.getKey().trim())){    // 로그 아웃 시킴

                        result = true;

                        return;

                }

            }

            System.out.println(“duplication result ” + result);

            if(!result){        // 로그인 정보가 없으면 날려버림

                response.sendRedirect(“/mngwsercgateway/duplicate/login.do”);

            }

    }

  • 인터셉터 부분 -**

 postHandler 안에 마지막에 선언. view단으로 가기전에 체크하도록 하기 위해서.. 무슨 이유인지는 개발 할때 당시 판단은 preHandler보다 postHandler에서 하는게 맞다고 생각이들었다.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

    /**

     * 중복 입력 방지 관련 메소드

     */

    public void duplicationLoginPrevent(HttpSession session, LoginVO loginVO, HttpServletResponse response) throws Exception{

        System.out.println(duplicate.getUserList());

        Hashtable loginUsers = duplicate.getUserList();

        Iterator<Map.Entry<String, String» itr = loginUsers.entrySet().iterator();

        // 비교할 세션 아이디

        String compareSessionId = session.getId();

        String loginId = loginVO.getId();

        String compareLoginId =””;

        boolean result = false;    // 결과

            while(itr.hasNext()){

                Map.Entry<String, String> user = itr.next();

                /**

                 *  로그인 중이였는데 다른 단말기에서 로그인하여 로그인을 취소할때.

                 *

                 *  세션아이디가 같은데 접속 계정이 다르면 alert

                 */

                compareLoginId = user.getValue();

                if(compareSessionId.equals(user.getKey().trim())){    // 로그 아웃 시킴

                        result = true;

                        return;

                }

            }

            System.out.println(“duplication result ” + result);

            if(!result){        // 로그인 정보가 없으면 날려버림

                response.sendRedirect(“/mngwsercgateway/duplicate/login.do”);

            }

    }

인터셉터에서 구현한 메서드이다.

저장된 계정 세션아이디랑 다른 값이 들어 있다면 다른 사람이 로그인했다고 판단.

중복접속이 되었다는 메시지를 뿌려주는 곳으로 이동하도록 설정하였다.

1

2

3

4

5

6

7

8

9

10

    /**

     * 중복 로그인시 거쳐가는 페이지

     * @param request

     * @return

     * @throws Exception

     */

    @RequestMapping(value=”/mngwsercgateway/duplicate/login.do”)

    public String duplicateLoginView (HttpServletRequest request) throws Exception{

        return ”error/duplicateLogin”;

    }

 - 중복 접속 관련 페이지 이동 -**

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<%@ page language=”java” contentType=”text/html; charset=UTF-8”

    pageEncoding=”UTF-8”%>

<!DOCTYPE html PUBLIC ”-//W3C//DTD HTML 4.01 Transitional//EN” ”http://www.w3.org/TR/html4/loose.dtd”>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 중복로그인 <script type="text/javascript">     alert("다른 곳에서 해당 계정으로 로그인되었습니다.\n로그아웃 처리 됩니다.");     location.href="/mngwserc/actionLogout.do"; </script>
  • 중복 접속 안내 페이지 내용 -**

  • 저장된 유저들 -**

static 변수로 저장해논 변수에 있는 값들도 로그 아웃 될때 이외에 브라우저 창을 닫을때 어떻게 처리할까 고민하였는데 unload 관련하여 브라우저마다 잘 동작하는게 아니라서

http://noritersand.tistory.com/146

sessionListener: 접속자 수 구하기web.xml 리스너 설정 com.util.CountManager //리스너는 이벤트를 활성화 servlet pu…noritersand.tistory.com

위 링크 참조하여 리스너 추가 후 세션 소멸 될때 해쉬테이블내에 세션아이디 값을 삭제하게 할려고 고민하였지만.. 나중으로 미루도록 했다.

추후에 적용할 예정.

이중화 된 was 쪽 적용 내용은 아래 링크를 참조.

http://blog.naver.com/PostView.nhn?blogId=kyong94s&logNo=119737344

http://blog.naver.com/kyong94s/119737344

[[세션관리] 로그인 세션관리 - 물리적으로 이중화된 서버 (물리적 분리)물리적으로 이중화되어 분리된 WAS 서버환경에서 로그인 세션을 관리(등록, 삭제)하는 방법은 세 가지로 정리할 수 있습니다.

데이터베이스 …blog.naver.com](http://blog.naver.com/kyong94s/119737344)

—————————————- 2015.09.04 ————————————–

web.xml 내에 listener 를 상속받은 클래스를 걸어줘야 된다.

그리고 사용자 정보를 세션에 저장하는 위치에서 해당 클래스를 같이 세션에 넣어줘야 정상적인 세션 체크 및 소멸이 가능해진다.

This article is licensed under CC BY 4.0 by the author.