同一帳號後者登陸前者被強制退出:(能夠經過監聽器或過濾器進行監測session是否無效)javascript
首先根據輸入的用戶名和密碼作驗證,經過驗證查詢用戶信息。在用戶信息不爲空的前提下,比較靜態變量中的sessionid和瀏覽器session獲取的getId(),判斷兩個值是否一致,若一致,則經過 正常走流程,若不一致,則返回登陸頁面,session設置msg,提示「帳戶失效或異地登陸」;
html
web.xml:java
<session-config> <session-timeout>180</session-timeout><!--session過時時間設置--> </session-config>
controller:web
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區別與聯繫ajax
方法一:(使用 HttpSessionListener進行監聽)瀏覽器
使用監聽器監聽對頁面跳轉很差進行控制session
web.xml:app
<!-- 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進行過濾)ide
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>