天天看點

Shiro攔截ajax請求

        今天又發現了一個新的問題,Shiro的攔截器不能夠攔截ajax請求,需要自定義一個攔截器來攔截ajax請求。

package com.ssi.domains.secutity;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.servlet.AdviceFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Created by jay.zhou on 2018/3/27.
 * 用于攔截ajax請求
 * 預設的Shiro配置檔案中攔截規則對發送的ajax請求無效
 * 是以必須自己做一個Shiro的過濾器
 * 這樣的話,ajax請求也會被Shiro攔截到
 * 本類可以預見到未來将會被複用多次
 * see:http://jinnianshilongnian.iteye.com/blog/2025656
 */
public final class AjaxFilter extends AdviceFilter {
    private static final Logger LOGGER = LoggerFactory.getLogger(AjaxFilter.class);
    /**
     * 前處理,這裡用于判斷這此請求是不是ajax請求
     *
     */
    @Override
    protected boolean preHandle(ServletRequest req, ServletResponse resp) 
throws Exception {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)resp;
        //擷取請求頭中的資訊,ajax請求最大的特點就是請求頭中多了 X-Requested-With 參數
        String requestType = request.getHeader("X-Requested-With");
        if("XMLHttpRequest".equals(requestType)){
            LOGGER.info("本次請求是AJAX請求!");
            //現在的用途就是判斷目前使用者是否被認證
            //先擷取到由Web容器管理的subject對象
            Subject subject = SecurityUtils.getSubject();
            //判斷是否已經認證
            boolean isAuthc = subject.isAuthenticated();
            if(!isAuthc){
                LOGGER.info("目前賬戶使用Shiro認證失敗!");
                //如果目前賬戶沒有被認證,本次請求被駁回,ajax進入error的function中進行重定向到登入界面。
                return false;
            }
            return true;
        }else{
            //如果請求類型不是ajax,那麼此時requestType為null
            LOGGER.info("非AJAX請求!");
        }
        //預設傳回的是true,将本次請求繼續執行下去
        return super.preHandle(request, response);
    }

    /**
     * 後處理,類似于AOP中的後置傳回增強
     * 在攔截器鍊執行完成後執行
     * 一般用于記錄時間。
     */
    @Override
    protected void postHandle(ServletRequest request, ServletResponse response) 
throws Exception {
        super.postHandle(request, response);
    }

    /**
     * 最終處理,一定會執行的,一般用于釋放資源。
     * 先留着
     */
    @Override
    public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) 
throws Exception {
        super.afterCompletion(request, response, exception);
    }
}      

        然後在配置檔案中配置上我們的攔截器即可。

[filters]
#預設的Shiro配置,對發送的ajax請求無效,是以需要自己做一個攔截器
myAjaxFilter=com.ssi.domains.secutity.AjaxFilter

[urls]
#評論子產品的操作需要登入
/actions/comment/**=myAjaxFilter,perms[comment]      

        希望能幫助你正在解決Shiro攔截不了ajax請求提供一個思路。

        在網上好多同僚在攔截器中傳回了Json資料,原因是ajax請求裡面的request和response對象是不支援轉發或者重定向的。

        我這裡沒有直接傳回Json資料,直接攔截住這個請求,沒有傳回success屬性,那麼ajax請求将會進入error的function中,執行重定向到登入頁面的操作。

        如何判斷一個請求是ajax請求。編寫像下面的代碼,從請求頭中擷取此參數資訊。如果這個requestType的值是:XMLHttpRequest  ,那麼這個請求是ajax請求。
String requestType = request.getHeader("X-Requset-With");      

        上圖為證明,本圖右下角。

Shiro攔截ajax請求

        按浏覽器F12,選中network,進入審查元素中,我們可以發現發送的accountLogin請求,是ajax請求。

        在Request Headers 請求頭中的相關資訊中, X-Request-With 的值是  XMLHttpRequest。