Shiro中session超時(shí)頁面跳轉(zhuǎn)的處理方式
session超時(shí)頁面跳轉(zhuǎn)的處理
問題描述
shiro在管理session后,在session超時(shí)會(huì)進(jìn)行跳轉(zhuǎn),這里有兩種情況需要考慮,一種是ajax方式的請(qǐng)求超時(shí),一種頁面跳轉(zhuǎn)請(qǐng)求的超時(shí)。
本文從這兩個(gè)方面分別考慮并處理。
ajax請(qǐng)求超時(shí)處理
思路:通過Filter后判定,當(dāng)前是否session超時(shí),超時(shí)判定是否是ajax請(qǐng)求,如果是ajax請(qǐng)求,則在response頭部設(shè)置session-status值,返回到前端讀取到相應(yīng)值后進(jìn)行處理
后端Filter代碼
package com.cnpc.framework.filter; import org.apache.shiro.SecurityUtils; import org.apache.shiro.session.Session; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * * filter過濾器,獲取項(xiàng)目路徑,設(shè)置ajax超時(shí)標(biāo)識(shí) * @author billJiang QQ:475572229 */ public class SystemFilter implements Filter { public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; System.out.println(request.getRequestURL()); String basePath = request.getContextPath(); request.setAttribute("basePath", basePath); if (!SecurityUtils.getSubject().isAuthenticated()) { //判斷session里是否有用戶信息 if (request.getHeader("x-requested-with") != null && request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) { //如果是ajax請(qǐng)求響應(yīng)頭會(huì)有,x-requested-with response.setHeader("session-status", "timeout");//在響應(yīng)頭設(shè)置session狀態(tài) return; } } filterChain.doFilter(request, servletResponse); } @Override public void destroy() { // TODO Auto-generated method stub } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
前端通用ajax處理
注意session-status上下文部分
function ajaxPost(url, params, callback) { var result = null; var headers={}; headers['CSRFToken']=$("#csrftoken").val(); $.ajax({ type : 'post', async : false, url : url, data : params, dataType : 'json', headers:headers, success : function(data, status) { result = data; if(data&&data.code&&data.code=='101'){ modals.error("操作失敗,請(qǐng)刷新重試,具體錯(cuò)誤:"+data.message); return false; } if (callback) { callback.call(this, data, status); } }, error : function(err, err1, err2) { console.log("ajaxPost發(fā)生異常,請(qǐng)仔細(xì)檢查請(qǐng)求url是否正確,如下面錯(cuò)誤信息中出現(xiàn)success,則表示csrftoken更新,請(qǐng)忽略"); console.log(err.responseText); if(err && err.readyState && err.readyState == '4'){ var sessionstatus=err.getResponseHeader("session-status"); if(sessionstatus=="timeout"){ //如果超時(shí)就處理 ,指定要跳轉(zhuǎn)的頁面 window.location.href=basePath+"/" ; } else{//csrf異常 var responseBody = err.responseText; if (responseBody) { responseBody = "{'retData':" + responseBody; var resJson = eval('(' + responseBody + ')'); $("#csrftoken").val(resJson.csrf.CSRFToken); this.success(resJson.retData, 200); } return; } } modals.error({ text : JSON.stringify(err) + ' err1:' + JSON.stringify(err1) + ' err2:' + JSON.stringify(err2), large : true }); } }); return result; }
非ajax請(qǐng)求超時(shí)跳轉(zhuǎn)
在本試驗(yàn)中,使用jquery.load方式進(jìn)行了頁面加載,并重載jquery.fn.load改寫了該方法,通過beforeSend去除了ajax標(biāo)識(shí),由于超時(shí)返回的登錄頁面可能嵌入當(dāng)前頁面,所以需要判斷當(dāng)前獲得的頁面是否是登錄頁面,如果是登陸頁面,則再經(jīng)過一次跳轉(zhuǎn)到登陸頁(或者首頁)。
重載的jquery.fn.load方法如下,注意beforeSend和responseText.startWith部分內(nèi)容。
var _old_load = jQuery.fn.load; jQuery.fn.load = function( url, params, callback ) { //update for HANZO, 2016/12/22 if (typeof url !== "string" && _old_load) { return _old_load.apply( this, arguments ); } var selector, type, response, self = this, off = url.indexOf( " " ); if ( off > -1 ) { selector = jQuery.trim( url.slice( off ) ); url = url.slice( 0, off ); } if ( jQuery.isFunction( params ) ) { callback = params; params = undefined; } else if ( params && typeof params === "object" ) { type = "POST"; } if ( self.length > 0 ) { jQuery.ajax( { url: url, beforeSend: function( xhr ) { xhr.setRequestHeader('X-Requested-With', {toString: function(){ return ''; }}); }, type: type || "GET", dataType: "html", data: params } ).done( function( responseText ) { //console.log(responseText); response = arguments; //頁面超時(shí)跳轉(zhuǎn)到首頁 if(responseText.startWith("<!--login_page_identity-->")){ window.location.href=basePath+"/"; }else{ self.html(selector ? jQuery("<div>").append(jQuery.parseHTML( responseText )).find(selector) : responseText); } } ).always( callback && function( jqXHR, status ) { self.each( function() { callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] ); } ); } ); } return this; };
可通過設(shè)置session的timeout來測(cè)試結(jié)果。需要注意的是ajax請(qǐng)求要使用ajaxPost方法,該方法統(tǒng)一處理了超時(shí)跳轉(zhuǎn)。
一個(gè)判斷session是否過期的小技巧
Session一直是我們做web項(xiàng)目經(jīng)常使用的,以前沒太注意,這次又細(xì)致的看了下!
1.session其實(shí)就是一個(gè)Map
鍵=值對(duì),通過session.getAttribute("name");獲得session中設(shè)置的參數(shù)
2.session的過期時(shí)間是從什么時(shí)候開始計(jì)算的?
是從一登錄就開始計(jì)算還是說從停止活動(dòng)開始計(jì)算?
答:從session不活動(dòng)的時(shí)候開始計(jì)算,如果session一直活動(dòng),session就總不會(huì)過期。
從該Session未被訪問,開始計(jì)時(shí); 一旦Session被訪問,計(jì)時(shí)清0;
3.設(shè)置session的失效時(shí)間
a)web.xml中
<session-config> ? ? ? ? <session-timeout>30</session-timeout> ? ? </session-config> ??
b)在程序中手動(dòng)設(shè)置
session.setMaxInactiveInterval(30 * 60);//設(shè)置單位為秒,設(shè)置為-1永不過期
c)tomcat也可以修改session過期時(shí)間,在server.xml中定義context時(shí)采用如下定義:
<Context path="/livsorder" docBase="/home/httpd/html/livsorder" ? defaultSessionTimeOut="3600" isWARExpanded="true" ? isWARValidated="false" isInvokerEnabled="true" ? isWorkDirPersistent="false"/> ?
4.如何判斷session過沒過期
request.getSeesion(boolean)方法,一下子讓我恍然大悟。這個(gè)方法里面?zhèn)髁艘粋€(gè)boolean值,這個(gè)值如果是true,那么如果當(dāng)前的request的session不可用,那么就創(chuàng)建新的會(huì)話,如果存在就返回當(dāng)前的會(huì)話。如果參數(shù)是false,那么在request的當(dāng)前會(huì)話不存在的時(shí)候就返回null。
這樣我們就可以很容易的聯(lián)想到這個(gè)所謂的request的當(dāng)前會(huì)話是否存在和session過期的聯(lián)系,所以我們就可以“近似地”認(rèn)為session不存在就是session過期了,那么我們就可以很容易地判斷session是否過期了。
方法如下:
if(request.getSession(false)==null) ? ?System.out.println("Session has been invalidated!"); else ? ?System.out.println("Session is active!");
可能大家注意到我上面有一個(gè)“近似地”字眼,也就是說存在特別情況。
這個(gè)特殊情況就是第一次請(qǐng)求還沒有創(chuàng)建會(huì)話的時(shí)候,那么用這個(gè)方法返回的仍然是null,原因我想大家應(yīng)該是顯然的。
private boolean checkSession(?? ?HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(false); String requestURI = request.getRequestURI(); String contextPath = request.getContextPath(); ? requestURI = requestURI.substring(contextPath.length()); ? if(requestURI.equals("/") || requestURI.equals("/login.jsp") || ??? ?requestURI.equals("/login.do")?? ?|| ??? ?requestURI.equals(this.errorPage)) return true; ? if(session != null? && session.getAttribute(this.objName) != null? && session.getAttribute("year") != null) return true; else? return false; }
比較好的一個(gè)辦法
//request.getSession(false)==null可以近似的判斷是否過期:如果已經(jīng)過期,那么返回的是null,但是當(dāng)起一次請(qǐng)求,剛剛建立一個(gè)session的時(shí)候,上述方法也返回null? //所以應(yīng)該這個(gè)做? if(null==request.getSession(false)){? ? ?if(true==request.getSession(true).isNew()){? ? ? ? }? else{? System.out.println("session已經(jīng)過期");? }? }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- spring boot整合redis實(shí)現(xiàn)shiro的分布式session共享的方法
- Spring Boot集成Shiro并利用MongoDB做Session存儲(chǔ)的方法詳解
- spring boot實(shí)戰(zhàn)教程之shiro session過期時(shí)間詳解
- Shiro+Redis實(shí)現(xiàn)登錄次數(shù)凍結(jié)的示例
- springboot整合shiro登錄失敗次數(shù)限制功能的實(shí)現(xiàn)代碼
- SpringBoot+Shiro學(xué)習(xí)之密碼加密和登錄失敗次數(shù)限制示例
- Shiro實(shí)現(xiàn)session限制登錄數(shù)量踢人下線功能
相關(guān)文章
Java簡(jiǎn)單統(tǒng)計(jì)字符串中漢字,英文字母及數(shù)字?jǐn)?shù)量的方法
這篇文章主要介紹了Java簡(jiǎn)單統(tǒng)計(jì)字符串中漢字,英文字母及數(shù)字?jǐn)?shù)量的方法,涉及java針對(duì)字符串的遍歷、編碼轉(zhuǎn)換、判斷等相關(guān)操作技巧,需要的朋友可以參考下2017-06-06Springboot之修改啟動(dòng)端口的兩種方式(小結(jié))
這篇文章主要介紹了Springboot之修改啟動(dòng)端口的兩種方式(小結(jié)),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09三行Java代碼實(shí)現(xiàn)計(jì)算多邊形的幾何中心點(diǎn)
因?yàn)楣ぷ餍枰?jì)算采煤機(jī)工作面的中心點(diǎn),如果套用數(shù)學(xué)的計(jì)算公式,用java去實(shí)現(xiàn),太麻煩了。本文將利用java幾何計(jì)算的工具包,幾行代碼就能求出多變形的中心,簡(jiǎn)直yyds!還不快跟隨小編一起學(xué)起來2022-10-10淺談HashMap、HashTable的key和value是否可為null
這篇文章主要介紹了淺談HashMap、HashTable的key和value是否可為null,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09springboot實(shí)現(xiàn)定時(shí)任務(wù)的四種方式小結(jié)
本文主要介紹了springboot實(shí)現(xiàn)定時(shí)任務(wù)的四種方式小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01java后臺(tái)啟動(dòng)jar包的一些命令匯總
這篇文章主要介紹了java后臺(tái)啟動(dòng)jar包的一些命令匯總,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-03-03