當我們採用SpringSecurity進行安全控制時,除了正常的基於瀏覽器地址欄的請求URL安全攔截之外,還會經常遇到AJAX調用受許可權攔 截的請求時傳回值不能處理的情況,按照預設的配置,如果AJAX請求的url需要使用者登入而使用者未登入或者會話已到期了,這時會被自動攔截並轉到登入介面 進行登入,這時,ajax請求實際上是返回了登入頁面的html代碼,這個代碼是不能進行json處理的。經過實驗,可以有兩個思路:
1、登入版面設定為某個 .do頁面,在這個頁面中做檢驗:
boolean isAjax = "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));
//如果是ajax請求
if (isAjax) {
String jsonObject = "{\"success\":false,\"isLoginRequired\":true}";
String contentType = "application/json";
response.setContentType(contentType);
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
out.print(jsonObject);
out.flush();
out.close();
return;
}
判斷如果是ajax過來的請求,則返回一個json格式的字串,用於前台處理。 前台如果是採用了jquery,可以擴充ajax請求,攔截所有的ajax請求的返回結果,進行全域處理:
(function($) {
// 備份jquery的ajax方法
var _ajax = $.ajax;
// 重寫jquery的ajax方法
$.ajax = function(opt) {
// 備份opt中error和success方法
var fn = {
error : function(XMLHttpRequest, textStatus, errorThrown) {
},
success : function(data, textStatus) {
}
};
if (opt.error) {
fn.error = opt.error;
}
if (opt.success) {
fn.success = opt.success;
}
// 擴充增強處理
var _opt = $.extend(opt, {
error : function(XMLHttpRequest, textStatus, errorThrown) {
// 錯誤方法增強處理
fn.error(XMLHttpRequest, textStatus, errorThrown);
},
success : function(data, textStatus) {
// 成功回調方法增強處理
if(data){
if (!data.success && data.isLoginRequired) {
showLoginWindow();
} else {
fn.success(data, textStatus);
}
}
}
});
_ajax(_opt);
};
})(jQuery);
function showLoginWindow() {
alert("請登入"); //可根據需要定製
}
這種方式有一個不太好的地方:ajax全域攔截之後,提示登入,然後就不會向下走了,這時如果彈出使用者登入框進行登入,則使用者登入成功之後,以前的操作不會繼續執行了,使用者需要重新再去操作一下。
2、
還有一種方案,原理類似: 在安全中配置一個<access-denied-handler
ref="accessDeniedHandler"/>,
但這個是存取拒絕的攔截處理,如果使用者還未登入,是不會被攔截的,可以考慮在使用者匿名訪問時,預設建立一個特殊的使用者物件,這個使用者權限是很低的,沒有普
通使用者的許可權,比如ROLE_USER,而我們一般會配置有許可權的資源要求最低是有ROLE_USER角色也就是普通使用者身份,這樣,當使用者請求這個資源
時,會被安全拒絕,通常預設是轉到403錯誤頁面,如果配置了access-denied-handler,那麼也可以轉到這個handler配置的一
個.do上去,再在這個do中按照上面的方法進行判斷處理。
這個方案不好的地方在於,不存在匿名使用者的說法了,因為通過使用者上下文來擷取目前使用者時,肯定會得到一個User對象。在這個handler中,需要處理使用者是否登入的情況,如果未登入,則轉到登入頁面進行登入,如果已登入,則轉到真正的403頁面,或者json串。