java web项目防止多用户重复登录解决方案

来源:互联网 发布:红鸟棋牌源码网盘下载 编辑:程序博客网 时间:2024/04/30 01:51

目前web项目中,很多情况都是可以让同一个账户信息在不同的登录入口登录这次,这样子就不那么美好了。

现在有两种解决方案:

1、将用户的登录信息用一个标志位的字段保存起来,每次登录成功就标记1,注销登录就标记为0,当标记为1的时候不允许别人登录。

2、将用户的登录信息保存在application内置作用域内, 然后利用session监听器监听每一个登录用户的登录情况。

很显然,第一种方式 每次登录 都需要操作数据库,多了一些不必要的性能开销,而且在登录状态下 万一突然电脑关闭了,那就永远都不能登录了,可用性比较低。

但是第二种方式就不一样了,可操作性强,很方便维护所有在线用户的信息。

接下来 主要介绍第二种方式的具体实现:

1、在处理登录的login方法中,先查询数据库验证下该用户是否存在,如果存在 判断该登录账户是否已经锁定了, 然后从application内置作用域对象中取出所有的登录信息,查看该username账户是否已经登录,如果登录了,就友好提示下,反之表示可以登录,将该登录信息保存在application中。

代码如下:

[java]

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
//没有使用零配置前 每个访问的方法都要加上@Action ,否则404  
@Action(value="login", results={ 
        @Result(name="index", location="index.jsp"), 
}) 
public String login() throws Exception { 
    try
        User result = userService.login(user.getFuUserName(), user.getFuPassword()); 
        if(result!=null){ 
            if(result.getFuStatus()!=null && result.getFuStatus()==0){ 
                super.setRequestAttr(Constant.MESSAGE, "抱歉,该用户已被锁定!"); 
                return "error"
            
            Map<String, String> loginUserMap = (Map<String, String>)super.getApplicationAttr(Constant.LOGIN_USER_MAP); 
            boolean isExist = false
            String sessionId = super.getSessionId(false); 
            if(loginUserMap==null){ 
                loginUserMap = new HashMap<String, String>(); 
            
            for (String username : loginUserMap.keySet()) { 
                //判断是否已经保存该登录用户的信息         并且     如果是同一个用户进行重复登录那么允许登录  
                if(!username.equals(result.getFuUserName()) || loginUserMap.containsValue(sessionId)){ 
                    continue
                
                isExist = true
                break
            }                
            if(isExist){ 
                super.setRequestAttr(Constant.MESSAGE, "抱歉,该用户已登录!"); 
                return "error"
            }else 
                loginUserMap.put(result.getFuUserName(), sessionId); 
            
            //登录成功  
            super.setSessionAttr(Constant.LOGIN_USER, result); 
            super.setApplicationAttr(Constant.LOGIN_USER_MAP, loginUserMap); 
                
            logger.info(result.getFuUserName() + " 登录成功!"); 
            //如果 session中fromUrl有值,就跳转到该页面  
            String fromUrl = (String)super.getSessionAttr(Constant.FROM_URL); 
            if(fromUrl!=null){ 
                super.setSessionAttr(Constant.FROM_URL, null); 
                super.getResponse().sendRedirect(fromUrl.toString()); 
                return null
            
            return "index"
        
    
    catch (Exception e) { 
        e.printStackTrace(); 
        logger.info("登录失败: "+e.getMessage()); 
    
    super.setRequestAttr("message""用户名或密码错误"); 
    return "error"
//没有使用零配置前 每个访问的方法都要加上@Action ,否则404
@Action(value="login", results={
@Result(name="index", location="index.jsp"),
})
public String login() throws Exception {
try{
User result = userService.login(user.getFuUserName(), user.getFuPassword());
if(result!=null){
if(result.getFuStatus()!=null && result.getFuStatus()==0){
super.setRequestAttr(Constant.MESSAGE, "抱歉,该用户已被锁定!");
return "error";
}
Map<String, String> loginUserMap = (Map<String, String>)super.getApplicationAttr(Constant.LOGIN_USER_MAP);
boolean isExist = false;
String sessionId = super.getSessionId(false);
if(loginUserMap==null){
loginUserMap = new HashMap<String, String>();
}
for (String username : loginUserMap.keySet()) {
//判断是否已经保存该登录用户的信息         并且     如果是同一个用户进行重复登录那么允许登录
if(!username.equals(result.getFuUserName()) || loginUserMap.containsValue(sessionId)){
continue;
}
isExist = true;
break;
}
if(isExist){
super.setRequestAttr(Constant.MESSAGE, "抱歉,该用户已登录!");
return "error";
}else {
loginUserMap.put(result.getFuUserName(), sessionId);
}
//登录成功
super.setSessionAttr(Constant.LOGIN_USER, result);
super.setApplicationAttr(Constant.LOGIN_USER_MAP, loginUserMap);
logger.info(result.getFuUserName() + " 登录成功!");
//如果 session中fromUrl有值,就跳转到该页面
String fromUrl = (String)super.getSessionAttr(Constant.FROM_URL);
if(fromUrl!=null){
super.setSessionAttr(Constant.FROM_URL, null);
super.getResponse().sendRedirect(fromUrl.toString());
return null;
}
return "index";
}
}
catch (Exception e) {
e.printStackTrace();
logger.info("登录失败: "+e.getMessage());
}
super.setRequestAttr("message""用户名或密码错误");
return "error";
}

2、登录入口处理完之后,考虑到回话结束的话,那么对应的登录用户也应该相应的注销登录。我们可以写一个Session监听器,监听sessioon销毁的时候,我们将登录的用户注销掉,也就是从application中移除。表示该用户已经下线了。

代码如下:

[java]

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
public class SessionListener implements HttpSessionListener,ServletContextListener{ 
    
    private int count; 
    private ServletContext servletContext = null
        
    public SessionListener() { 
        count = 0
    
    
    private Logger logger = Logger.getLogger(this.getClass()); 
    @Override
    public void sessionCreated(HttpSessionEvent event) { 
        count++; 
        setContext(event); 
        logger.info("***************the  http session is created...***************"); 
    
    
    @Override
    public void sessionDestroyed(HttpSessionEvent event) { 
        //在session销毁的时候 把loginUserMap中保存的键值对清除  
        User user = (User)event.getSession().getAttribute("loginUser"); 
        if(user!=null){ 
            Map<String, String> loginUserMap = (Map<String, String>)event.getSession().getServletContext().getAttribute("loginUserMap"); 
            loginUserMap.remove(user.getFuUserName()); 
            event.getSession().getServletContext().setAttribute("loginUserMap",loginUserMap); 
        
            
        count--; 
        setContext(event); 
        logger.info("***************the  http session is destroyed...***************"); 
    
    
    public void setContext(HttpSessionEvent httpSessionEvent){ 
        httpSessionEvent.getSession().getServletContext().setAttribute("online", count); 
    
        
        
    @Override
    public void contextDestroyed(ServletContextEvent servletcontextevent) {      
        this.servletContext = null
        logger.info("***************the  servlet context is destroyed...***************"); 
    
    
    @Override
    public void contextInitialized(ServletContextEvent servletcontextevent) { 
        this.servletContext = servletcontextevent.getServletContext(); 
        logger.info("***************the  servlet context is initialized...***************"); 
    
public class SessionListener implements HttpSessionListener,ServletContextListener{
private int count;
private ServletContext servletContext = null;
public SessionListener() {
count = 0;
}
private Logger logger = Logger.getLogger(this.getClass());
@Override
public void sessionCreated(HttpSessionEvent event) {
count++;
setContext(event);
logger.info("***************the  http session is created...***************");
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
//在session销毁的时候 把loginUserMap中保存的键值对清除
User user = (User)event.getSession().getAttribute("loginUser");
if(user!=null){
Map<String, String> loginUserMap = (Map<String, String>)event.getSession().getServletContext().getAttribute("loginUserMap");
loginUserMap.remove(user.getFuUserName());
event.getSession().getServletContext().setAttribute("loginUserMap",loginUserMap);
}
count--;
setContext(event);
logger.info("***************the  http session is destroyed...***************");
}
public void setContext(HttpSessionEvent httpSessionEvent){
httpSessionEvent.getSession().getServletContext().setAttribute("online", count);
}
@Override
public void contextDestroyed(ServletContextEvent servletcontextevent) {
this.servletContext = null;
logger.info("***************the  servlet context is destroyed...***************");
}
@Override
public void contextInitialized(ServletContextEvent servletcontextevent) {
this.servletContext = servletcontextevent.getServletContext();
logger.info("***************the  servlet context is initialized...***************");
}
web.xml中配置如下:
[html] view plaincopyprint?
<!-- session listener --> 
<listener> 
    <listener-class>com.facelook.util.SessionListener</listener-class
</listener> 
<!-- session listener -->
<listener>
<listener-class>com.facelook.util.SessionListener</listener-class>
</listener>

3、另外,还有一个问题,如果说登录的用户突然关闭了浏览器而没有点击退出按钮。那么可以利用beforeunload 事件,在浏览器刷新或者关闭的时候触发。

[java]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//在刷新或关闭时调用的事件  
$(window).bind('beforeunload',function(){ 
  $.ajax({ 
    url:"${ctx}/system/user/user!logout.action"
    type:"post"
    success:function(){ 
        alert("您已退出登录"); 
    
}); 
); 
  //在刷新或关闭时调用的事件
  $(window).bind('beforeunload',function(){
   $.ajax({
url:"${ctx}/system/user/user!logout.action",
type:"post",
success:function(){
alert("您已退出登录");
}
});
});

这样子,基本上可以实现防止多用户登录的案例了!

0 0