同一账号后者登录前者被强制退出:(可以通过监听器或过滤器进行监测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>