zoukankan      html  css  js  c++  java
  • 站点单用户登录,后面登录上来的会把前面登录的人踢下线

    公司平台接受监管后,系统整改,其中一个就是一个用户账号只能在一个地方登录,别的地方登录上来后,当前登录的人必须下线。

    因为一直做web开发,之前给某公司做过这个功能,只不过那个是8年前,比较老的方式,单体系统,目前都是分布式。但是其实实现原理都是一样的。分布式系统只是部署了多份app。那么就得依赖一个第三方存储的地方,可以是db,可以是缓存。这里我就用缓存redis。

    首先说一下这个单账号只能一个ip登录的原理:

    明天继续。先贴代码:

    LoginAloneHttpSessionListener.java

    import javax.servlet.ServletContext;
    import javax.servlet.annotation.WebListener;
    import javax.servlet.http.HttpSession;
    import javax.servlet.http.HttpSessionAttributeListener;
    import javax.servlet.http.HttpSessionBindingEvent;
    import javax.servlet.http.HttpSessionEvent;
    import javax.servlet.http.HttpSessionListener;
    
    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.data.redis.core.BoundHashOperations;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.support.WebApplicationContextUtils;
    
    
    @Component
    @WebListener
    public class LoginAloneHttpSessionListener implements HttpSessionListener,  HttpSessionAttributeListener {
        
        private static Logger logger = Logger.getLogger(LoginAloneHttpSessionListener.class);
    
        @Autowired
        private StringRedisTemplate stringRedisTemplate;
        
        /**初始化方法 stringRedisTemplate
         * 
         * @param session
         * @author chenweixian 陈惟鲜
         * @date 2018年2月26日 上午10:40:02
         */
        public void initStringRedisTemplate(HttpSession session){
            if (stringRedisTemplate == null){
                ServletContext servletContext = session.getServletContext();  
                ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
                stringRedisTemplate = context.getBean("stringRedisTemplate", StringRedisTemplate.class);
            }
        }
    
        @Override
        public void sessionCreated(HttpSessionEvent event) {
            this.initStringRedisTemplate(event.getSession());
            
    //        logger.info("============session【"+event.getSession().getId()+"】 已创建");
        }
    
        @Override
        public void sessionDestroyed(HttpSessionEvent event) {
            this.initStringRedisTemplate(event.getSession());
            BoundHashOperations<String, String, String> boundHashOperations = stringRedisTemplate.boundHashOps(RedisContants.ADMIN_LOGIN_MAP);
            boundHashOperations.delete(event.getSession().getId());
            
    //        logger.info("============session【"+event.getSession().getId()+"】 已销毁");
        }
    
        @Override
        public void attributeAdded(HttpSessionBindingEvent event) {
    
            this.handleUserInfo(event);
            
    //        logger.info("============session【"+event.getSession().getId()+"】====attribute  Added");
            
        }
    
        @Override
        public void attributeRemoved(HttpSessionBindingEvent event) {
            if (SystemContants.USER_INFO.equals(event.getName())){
                this.initStringRedisTemplate(event.getSession());
                BoundHashOperations<String, String, String> boundHashOperations = stringRedisTemplate.boundHashOps(RedisContants.ADMIN_LOGIN_MAP);
                boundHashOperations.delete(event.getSession().getId());
            }
            
    //        logger.info("============session【"+event.getSession().getId()+"】====attribute Removed");
        }
    
        @Override
        public void attributeReplaced(HttpSessionBindingEvent event) {
            this.handleUserInfo(event);
    
    //        logger.info("============session【"+event.getSession().getId()+"】=====attribute Replaced");
            
        }  
        
        /**处理用户信息
         * 
         * @param event
         * @author chenweixian 陈惟鲜
         * @date 2018年2月26日 上午11:07:11
         */
        private void handleUserInfo(HttpSessionBindingEvent event){
            if (SystemContants.USER_INFO.equals(event.getName())){
                this.initStringRedisTemplate(event.getSession());
                UserVo userVo = (UserVo)event.getValue();
                BoundHashOperations<String, String, String> boundHashOperations = stringRedisTemplate.boundHashOps(RedisContants.ADMIN_LOGIN_MAP);
                // 踢出之前在线的用户
                if (userVo != null){
                    if (boundHashOperations.keys().size() > 0){
                        for (String key :  boundHashOperations.keys()){
                            if(userVo.getUserId().equalsIgnoreCase(boundHashOperations.get(key))){
                                // 踢出
                                boundHashOperations.delete(key);
                            }
                        }
                    }
                }
    
                // 加入当前登录用户
                boundHashOperations.put(event.getSession().getId(), userVo.getUserId());
            }
        }
        
    }

    LoginFilter.java

    import java.io.IOException;
    import java.util.regex.Pattern;
    
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.log4j.Logger;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.ApplicationContext;
    import org.springframework.data.redis.core.BoundHashOperations;
    import org.springframework.data.redis.core.StringRedisTemplate;
    import org.springframework.stereotype.Service;
    import org.springframework.web.context.support.WebApplicationContextUtils;
    import com.opensymphony.oscache.util.StringUtil;
    
    /**登录过滤器
     * 
     * @author : chewneixian 陈惟鲜
     * @create_date 2016年8月3日 上午11:35:23
     *
     */
    @Service
    @WebFilter(filterName="loginFilter", urlPatterns={
            "*.do",
            })
    public class LoginFilter implements Filter {
        @Autowired
        private DictionaryVoService dictionaryVoService;
        // 忽略的URL
    //    String PASS_VALIDATION_URL = ConfigPropertiesUtil.getProp("login.ignore.passUrl");
    
        //     日志对象
        private static Logger logger = Logger.getLogger(LoginFilter.class);
        @Autowired
        private StringRedisTemplate stringRedisTemplate;
    
        public void init(FilterConfig filterConfig) throws ServletException {
            ServletContext servletContext = filterConfig.getServletContext();  
            ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
            if (stringRedisTemplate == null){
                stringRedisTemplate = context.getBean("stringRedisTemplate", StringRedisTemplate.class);
            }
            if (dictionaryVoService == null){
                dictionaryVoService = context.getBean("dictionaryVoService", DictionaryVoService.class);
            }
        }
        
        public void destroy() {
        }
    
        public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;        
            String PASS_VALIDATION_URL = dictionaryVoService.findFieldValue(DictionaryContants.TYPE_ID_PLATFORM_INFO, StatusContants.LOGIN_IGNORE_PASSURL.getIndex());
    
            // 是否跳过检查
            String requestUri = request.getRequestURI();
            requestUri = requestUri.replace(request.getContextPath()+"/", ""); // 去掉工程名/
            if (Pattern.matches(PASS_VALIDATION_URL,requestUri)) {
                chain.doFilter(req, res);
                return ;
            }
            // 获取登录用户信息
            UserVo userVo = (UserVo)request.getSession().getAttribute(SystemContants.USER_INFO);
            if (userVo == null){
                // 用户未登录
                logger.error("您未登录,或登录超时,或您的账号在其他地方登录");
                response.sendRedirect(request.getContextPath() + "/login_to.do");
                return ;
            }
            if (!this.isLogined(request.getSession().getId(), userVo.getUserId())){
                // 用户未登录
                logger.error("您的账号已经在异地登录,请重新登录修改密码。");
                response.sendRedirect(request.getContextPath() + "/login_error.do");
                return ;
            }
            
            chain.doFilter(req, res);
        }
        
         /** 
           * isLogining-用于判断用户是否已经登录 
           * @param        sessionUserName String-登录的用户名 
           * @return boolean-该用户是否已经登录的标志 
           * */  
          public boolean isLogined(String nowSessionId, String nowUserId){  
              boolean result = false;
            BoundHashOperations<String, String, String> boundHashOperations = stringRedisTemplate.boundHashOps(RedisContants.ADMIN_LOGIN_MAP);
            if (boundHashOperations.keys().size() > 0){
                // 当前登线程用户ID, 在集合中没有记录
                String sessionUserId = boundHashOperations.get(nowSessionId); 
                if (!StringUtil.isEmpty(sessionUserId)){
                    // 当前使用这个用户ID的线程ID
                    String mySessionId = "";
                    for (String key :  boundHashOperations.keys()){
                        if(nowUserId.equalsIgnoreCase(boundHashOperations.get(key))){
                            mySessionId = key;
                            break;
                        }
                    }
                    // 当前线程与登录用户线程ID相等,则登录
                    if (nowSessionId.equals(mySessionId)){
                        result = true;
                    }
                }
            }
            return result;
          }
        
    }
  • 相关阅读:
    leetcode116 Populating Next Right Pointers in Each Node
    leetcode171 Excel Sheet Column Number
    Js 之生成二维码插件(jquery.qrcode.js)
    Js 之cookie插件(jquery.cookie.js)
    Js 之常见手势操作插件 Hammer.js
    快速购买系统
    PHP + CI框架 + AdminLITE权限管理系统
    PHP 之查找字符串位置函数封装
    利用layer制作好看的弹出框
    PHP+CI框架+Memcache集成
  • 原文地址:https://www.cnblogs.com/a393060727/p/8489648.html
Copyright © 2011-2022 走看看