當我們采用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串。