1. 程式人生 > >Shiro中session超時頁面跳轉的處理

Shiro中session超時頁面跳轉的處理

問題描述

shiro在管理session後,在session超時會進行跳轉,這裡有兩種情況需要考慮,一種是ajax方式的請求超時,一種頁面跳轉請求的超時。

本文從這兩個方面分別考慮並處理。

ajax請求超時處理

思路:通過Filter後判定,當前是否session超時,超時判定是否是ajax請求,如果是ajax請求,則在response頭部設定session-status值,返回到前端讀取到相應值後進行處理

後端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過濾器,獲取專案路徑,設定ajax超時標識 * @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請求響應頭會有,x-requested-with response.setHeader("session-status", "timeout");//在響應頭設定session狀態 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("操作失敗,請重新整理重試,具體錯誤:"+data.message);
                return false;
            }
            if (callback) { 
                callback.call(this, data, status);
            }
        },
        error : function(err, err1, err2) {
            console.log("ajaxPost發生異常,請仔細檢查請求url是否正確,如下面錯誤資訊中出現success,則表示csrftoken更新,請忽略");
            console.log(err.responseText);
            if(err && err.readyState && err.readyState == '4'){
                var sessionstatus=err.getResponseHeader("session-status");
                if(sessionstatus=="timeout"){
                    //如果超時就處理 ,指定要跳轉的頁面
                    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) + '<br/>err1:' + JSON.stringify(err1) + '<br/>err2:' + JSON.stringify(err2),
                large : true
            });
        }
    });

    return result;
}

非ajax請求超時跳轉

在本試驗中,使用jquery.load方式進行了頁面載入,並重載jquery.fn.load改寫了該方法,通過beforeSend去除了ajax標識,由於超時返回的登入頁面可能嵌入當前頁面,所以需要判斷當前獲得的頁面是否是登入頁面,如果是登陸頁面,則再經過一次跳轉到登陸頁(或者首頁)。

過載的jquery.fn.load方法如下,注意beforeSendresponseText.startWith部分內容。

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;
            //頁面超時跳轉到首頁
            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;
};

可通過設定session的timeout來測試結果。需要注意的是ajax請求要使用ajaxPost方法,該方法統一處理了超時跳轉。