java-同一用户顶替操作(session过期或无效)

同一账号后者登录前者被强制退出:(可以通过监听器或过滤器进行监测session是否无效)

首先根据输入的用户名和密码做验证,通过验证查询用户信息。在用户信息不为空的前提下,比较静态变量中的sessionid和浏览器session获取的getId(),判断两个值是否一致,若一致,则通过 正常走流程,若不一致,则返回登录页面,session设置msg,提示“账户失效或异地登录”;

web.xml:

<session-config>
        <session-timeout>180</session-timeout><!--session过期时间设置-->
</session-config>

controller:

    public static Map<HttpSession, String> loginSessionList = new HashMap<>();//保存当前登录的所有用户

    //登录方法
    @ResponseBody
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public ResponseResult login(User user, HttpServletRequest request,HttpSession session) {
          //.............................
            session.setAttribute("username", user.getLoginName());
            session.setAttribute("logoutType", "0");
            checkLoginSession(session,user.getLoginName());
            loginSessionList.put(session, user.getLoginName());
          //.............................  
    
     }

     /**
     * 检查用户是否已经登录
     * @param session
     * @param loginName
     * @return
     */
    private String checkLoginSession(HttpSession session,String loginName) {
        String checkValue = "0";
        HttpSession reSession = null;
        try {
            Set<HttpSession> keys = loginSessionList.keySet();
            for (HttpSession key : keys) {
                if (loginSessionList.get(key).equals(loginName) && !session.equals(key)) {
                    //key.invalidate();//如果该用户名有登录,则使前者失效(适用于方法一)
                    key.setAttribute("logoutType", "1");
                    checkValue = "1";
                    reSession = key;
                    break;
                }
            }
            if (checkValue.equals("1") && reSession != null) {
                //防止用户直接关闭浏览器
                loginSessionList.remove(reSession);
            }
        } catch (Exception e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        return null;
    }

参考链接:servlet/filter/listener/interceptor区别与联系

方法一:(使用 HttpSessionListener进行监听)

使用监听器监听对页面跳转不好进行控制

web.xml:

<!-- session监听  -->
    <listener>
          <listener-class>net.nblh.system.shiro.OnlineUserListener</listener-class><!--监听器类的路径-->
    </listener>

 OnlineUserListener:

package net.nblh.system.shiro;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import net.nblh.system.controller.SystemController;

public class OnlineUserListener implements HttpSessionListener{

    /**
     * 监听session创建
     */
    @Override
    public void sessionCreated(HttpSessionEvent arg0) {
        // TODO 自动生成的方法存根
        
    }

    /**
     * 监听session销毁
     */
    @Override
    public void sessionDestroyed(HttpSessionEvent event){
        try {
            // TODO 自动生成的方法存根
            HttpSession session = event.getSession();
            // 取得登录的用户名
            String username = (String) session.getAttribute("username");
            SystemController.loginSessionList.remove(session);
            System.out.println(username + "退出。");
        } catch (Exception e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
        
    }
    
}

方法二:(使用Filter进行过滤)

web.xml:

<!-- session过滤器 -->
    <filter>
        <filter-name>sessionFilter</filter-name>
        <filter-class>net.nblh.system.shiro.SessionFilter</filter-class><!--过滤器类的路径-->
    </filter>
    <filter-mapping>
            <filter-name>sessionFilter</filter-name>
            <url-pattern>/*</url-pattern>
    </filter-mapping>

SessionFilter:

package net.nblh.system.shiro;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.nblh.system.controller.SystemController;
import net.nblh.system.entity.SysConfigItemValue;
import net.nblh.utils.StringUtils;

/**
 * Session拦截器
 * @author lijd
 *
 */
public class SessionFilter implements Filter {

    @Override
    public void destroy() {
        // TODO 自动生成的方法存根

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        try {
            // TODO 自动生成的方法存根
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            HttpSession session = httpRequest.getSession();

            //异地顶替账号登录url
            String toLoginUrl = session.getServletContext().getContextPath()+"/system/tologin2";//列席人登录页面
            //session过期登录url
            String sessionLoginUrl = StringUtils.isNotEmpty(SysConfigItemValue.getValue("sessionOutTimeToURL"))?SysConfigItemValue.getValue("sessionOutTimeToURL"):toLoginUrl;
            String url = httpRequest.getRequestURI();
            String path = url.substring(url.lastIndexOf("/"));
            /*// 判断是否为ajax请求
            if (httpRequest.getHeader("x-requested-with") != null && httpRequest.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
                //该请求是 AJAX 异步HTTP请求
                if (session.getAttribute("shiroSavedRequest") != null && session.getAttribute("currentUser") == null) {
                    SystemController.loginSessionList.remove(session);
                    session.invalidate();
                    httpResponse.addHeader("sessionstatus", "timeOut");//Session已过期
                    httpResponse.addHeader("loginPath", sessionLoginUrl);
                    chain.doFilter(request, response);
                }else {
                    chain.doFilter(request, response);// 不可少,否则请求会出错
                }
            }*/
            if (path.indexOf("sessionTimeOut") != -1 && session.getAttribute("shiroSavedRequest") != null && session.getAttribute("currentUser") == null) {
                SystemController.loginSessionList.remove(session);
                session.invalidate();
                //session过期
                toLoginUrl(response,"会话已过期",sessionLoginUrl);
            }         
            else if(session.getAttribute("logoutType") != null && session.getAttribute("logoutType").equals("1")){
                SystemController.loginSessionList.remove(session);
                session.invalidate();
                // logoutType=0:正常,logoutType=1:异地登录                
                toLoginUrl(response,"用户已在别处登录",toLoginUrl);
            } else {
                try {
                    chain.doFilter(request, response);
                } catch (Exception e) {
                    SystemController.loginSessionList.remove(session);
                    session.invalidate();
                    toLoginUrl(response,"会话已过期!",sessionLoginUrl);
                }
            }
        } catch (Exception e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
        }
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {
        // TODO 自动生成的方法存根

    }

    /**
     * session无效后跳转指定路径
     * @param response
     * @param message
     * @param loginUrl
     */
    private void toLoginUrl (ServletResponse response,String message,String loginUrl) {
        String str = "<script language='javascript'>alert('"+ message +"');" + "top.location.href='" + loginUrl + "';</script>";
        response.setContentType("text/html;charset=UTF-8");// 解决中文乱码
        try {
            PrintWriter writer = response.getWriter();
            writer.write(str);
            writer.flush();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

使用响应头进行JS控制:

httpResponse.addHeader("sessionstatus", "timeOut");//Session已过期
httpResponse.addHeader("loginPath", sessionLoginUrl);
chain.doFilter(request, response);

js:

<script type="text/javascript">
$(document).ajaxComplete(function(event, xhr, settings) {  
    if(xhr.getResponseHeader("sessionstatus")=="timeOut"){  
        if(xhr.getResponseHeader("loginPath")){
            alert("会话过期,请重新登陆!");
            window.location.replace(xhr.getResponseHeader("loginPath"));  
        }else{  
            alert("请求超时请重新登陆 !");  
        }  
    }  
});  
</script>

 

posted on 2019-04-10 21:43  LJD泊水  阅读(1286)  评论(0编辑  收藏  举报