所以我一直在使用 Grails 的 Spring Security,我玩得很开心,但我在通过 AJAX 登录的一件小事上遇到了麻烦。我有一个登录表单发布到 /j_spring_security_check
通过 AJAX 登录,它工作得很好,但是当我进入登录页面 1) 直接,2) 当我尝试访问安全时被重定向到登录页面时,我对不同的响应感到困惑页。登录页面是/login/auth
, 我替换了 auth.gsp
中的标准表格使用 AJAXified 形式。下面是两种情况:
/login/auth
直接,当我这样做并使用 AJAX 登录时,我会返回标准的 JSON 对象,即我得到类似 {"success":true,"username":"charles"}
的信息。或 {"error":"Sorry, we were not able to find a user with that username and password."}
- 没有意外 - 一切都很好。 /login/auth
当我浏览到我的应用程序中的另一个 Controller /操作(如 /users/list
)并且我没有通过身份验证时,是“该”登录页面我被重定向到 /login/auth
,正如预期的那样。因此,当我输入虚假凭据时,我会返回 {"error":"Sorry, we were not able to find a user with that username and password."}
,正如预期的那样,但是当我使用正确的凭据登录时,我会在响应正文中返回原始请求页面的实际 HTML。理想情况下,我想找回类似 {"success":true,"username":"charles", referer:"/users/list"}
的东西。 - 这样我的登录表单就可以做很酷的动画,然后重定向到最初请求的 URL。我知道发生了什么,在第 1 种情况 ajaxSuccess()
在 LoginController.groovy
被调用(返回 JSON) - 但在这种情况下它不会被调用,而且我无法找出调用的是什么,以便我可以破解它来做我想做的事。 有一个更好的方法吗?或者有人可以指出我正确的方向吗?我将不胜感激任何帮助!
非常感谢!
:)
如果有帮助,这是我的 AJAX 调用,尽管它非常标准:
<script>
$(document).ready(function(){
$("#submit").click(function(){
$("#response").html("Attempting login...");
var formdata = $('#loginForm').serialize();
$.ajax({
url: "/UserDemo/j_spring_security_check",
type: 'post',
data: formdata,
success: function(r){
if (r.success) {
$("#response").html("Success!");
} else if (r.error) {
$("#response").html(r.error);
}
}
});
});
});
最佳答案
基本上问题是,即使对于 ajax 请求,当来自另一个 url 时,Spring 的 SavedRequestAwareAuthenticationSuccessHandler 重定向到完整页面。
您可以在浏览器调试工具中看到这一点,但由于 ajax 请求的工作方式(透明重定向),您无法规避/阻止重定向。
可能有更好的方法,但以下方法有效。 ajax 请求的重定向更改如下:
将此类放入 source/groovy
class AjaxSuccessAwareRedirectStragegy extends DefaultRedirectStrategy {
private String _ajaxSuccessUrl;
public void sendRedirect(HttpServletRequest request, HttpServletResponse response, String url) throws IOException {
if (SpringSecurityUtils.isAjax(request)) {
if (url != _ajaxSuccessUrl) {
url = _ajaxSuccessUrl + "?targetUrl=" + URLEncoder.encode(url, 'UTF-8')
}
super.sendRedirect(request, response, url)
} else {
super.sendRedirect(request, response, url)
}
}
public void setAjaxSuccessUrl(final String ajaxSuccessUrl) {
_ajaxSuccessUrl = ajaxSuccessUrl;
}
}
然后将在 *AuthenticationSuccessHandler 上使用这种特殊的重定向策略。为了注册它,将此配置放入 resources.groovy(AjaxSuccessAwareRedirectStragegy 正是与此用例相关的配置)
beans = {
def conf = SpringSecurityUtils.securityConfig
authenticationSuccessHandler(AjaxAwareAuthenticationSuccessHandler) {
//borrowed from DefaultSecurityConfig.groovy
requestCache = ref('requestCache')
defaultTargetUrl = conf.successHandler.defaultTargetUrl // '/'
alwaysUseDefaultTargetUrl = conf.successHandler.alwaysUseDefault // false
targetUrlParameter = conf.successHandler.targetUrlParameter // 'spring-security-redirect'
ajaxSuccessUrl = conf.successHandler.ajaxSuccessUrl // '/login/ajaxSuccess'
useReferer = conf.successHandler.useReferer // false
redirectStrategy = ref('ajaxSuccessAwareRedirectStrategy')
}
ajaxSuccessAwareRedirectStrategy(AjaxSuccessAwareRedirectStragegy) {
contextRelative = conf.redirectStrategy.contextRelative
ajaxSuccessUrl = conf.successHandler.ajaxSuccessUrl
}
}
瞧,在您的 LoginController 中,您可以将 ajaxSuccess 操作更改为使用 targetUrl,然后可以在您的登录 Javascript 中使用它
def ajaxSuccess = {
def redirect = params.targetUrl
println "LoginControllerAjaxAuthParams " + params
render([success: true, username: springSecurityService.authentication.name] << (redirect ? [redirect: redirect] : [:]) as JSON)
}
关于ajax - Grails Spring Security AJAX 响应请求页面的 HTML,而不是来自 ajaxSuccess() 的 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20026148/