ajax - Grails Spring Security AJAX 响应请求页面的 HTML,而不是来自 ajaxSuccess() 的 JSON

标签 ajax grails spring-security

所以我一直在使用 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/

    相关文章:

    grails - 在grails应用程序之间共享resources.groovy

    java - 无法在 Spring Boot 2.0.1 中禁用 Spring Security

    rest - 我如何使用 Controller 来在grails 2.3.1中使用rest api?

    ajax - CakePHP 使用 ajax 加载模态内容

    javascript - 什么是最简单、最著名、最老练的 AJAX 框架?

    javascript - 获取文本的 JavaScript 变量并将它们用作隐藏输入

    java - 没有jsp的Spring安全

    javascript - jquery 使用多个 if/else 条件验证规则

    Grails - 使用路由隐藏/index 操作

    grails - Grails 2.3 domain.encodeAsHTML()从domain.equals()引发空指针异常