当我们采用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串。
|