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>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM