Spring Security - 所有 JQuery Ajax 发布请求都返回 404

Posted

技术标签:

【中文标题】Spring Security - 所有 JQuery Ajax 发布请求都返回 404【英文标题】:Spring Security - All JQuery Ajax post requests return 404 【发布时间】:2015-05-13 04:48:13 【问题描述】:

我所有的$.ajaxPOSTGET 都工作正常,但是一旦我将Spring security 3.2.6 集成到我的项目中,POST ajax 请求就会停止工作,而不会出现任何登录问题。

spring-security.xml

<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns="http://www.springframework.org/schema/security"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security-3.2.xsd">

    <!--Permit all Web resources to bypass proxy-->
    <http pattern="/js/**" security="none"/>
    <http pattern="/css/**" security="none"/>
    <http pattern="/fonts/**" security="none"/>
    <http pattern="/images/**" security="none"/>

    <http auto-config="true" use-expressions="true" >

        <intercept-url pattern="/login" access="isAnonymous()"/>

        <intercept-url pattern="/workflow**" access="hasRole('ROLE_WORKFLOW_ADMIN')"/>
        <intercept-url pattern="/**" access="hasAnyRole('ROLE_ADMIN','ROLE_WORKFLOW_ADMIN','ROLE_DMS_ADMIN')"/>

        <access-denied-handler error-page="/403"/>

        <form-login
                login-page="/login"
                default-target-url="/dashboard"
                authentication-failure-url="/login?error"
                username-parameter="username"
                password-parameter="password"/>

        <logout invalidate-session="true" logout-success-url="/login?logout"/>

        <csrf/>
    </http>

    <!-- Select users and user_roles from database -->
    <authentication-manager>
        <authentication-provider ref="daoAuthenticationProvider"/>
    </authentication-manager>

    <beans:bean id="daoAuthenticationProvider"
                class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <beans:property name="userDetailsService" ref="authService"/>
    </beans:bean>


</beans:beans>

Web.xml

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         version="2.5">

    <filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/mvc-dispatcher-servlet.xml
            /WEB-INF/spring-security.xml
        </param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <error-page>
        <exception-type>java.lang.Throwable</exception-type>
        <location>/error</location>
    </error-page>
    <error-page>
        <error-code>500</error-code>
        <location>/error</location>
    </error-page>

</web-app>

编辑


我要访问的网址是

http://localhost:8080/ADMIN/workflow/sample-ajax

这可能与弹簧安全有关吗?

【问题讨论】:

请分享您从 ajax 请求中访问的 URL。 POST ajax 请求停止...不是说明性问题陈述。但是控制台中是否有错误。您的网址可能会发生一些变化。 @Mithun - 见我上面的编辑 根据配置,URL匹配的/workflow**应该有ROLE_WORKFLOW_ADMIN角色。您能否确认您使用的用户是否属于该角色? 【参考方案1】:

终于在痛苦的三天之后,我发现了问题,男孩是不是很愚蠢。

问题是我在 spring security 中启用了csrf 保护。这导致我的帖子请求被禁止触发access-denied-handler错误页面,因为我没有将我的access-denied-handler映射到"/403"错误页面,如下所示,我的http 403/401被@987654326掩盖@

<access-denied-handler error-page="/403"/>

总之

    将您的access-denied-handler 错误页面映射到有效的网址 如果您使用 csrf 保护,请始终确保在 ajax 发布请求中传递它们

$.ajax(method :'POST', url : '/ajax',data : "$_csrf.parameterName" : "$_csrf.token");

【讨论】:

【参考方案2】:

在实现spring security 4时还有一种情况需要特别参考,需要表单按钮(不是“a href”)。

https://spring.io/blog/2013/08/21/spring-security-3-2-0-rc1-highlights-csrf-protection/#ajax-requests.

A> 已发送表单发布请求:输入类型隐藏在两个登录/注销按钮

<input type="hidden" name="$_csrf.parameterName" value="$_csrf.token"/>

B> 对于 AJAX 发布请求,在您的 JSP 页面中在 taglib 声明之后添加以下内容。

<meta name="_csrf" content="$_csrf.token" />
<meta name="_csrf_header" content="$_csrf.headerName" />

还有一些在jsp中关闭body标签的地方,因为它“准备就绪”

<script type="text/javascript">
$(function() 
    var token = $("meta[name='_csrf']").attr("content");
    var header = $("meta[name='_csrf_header']").attr("content");
    $(document).ajaxSend(function(e, xhr, options) 
        xhr.setRequestHeader(header, token);
    );
);
 </script>

它应该工作! 如果您仍然存在 CORS 问题,请参阅下面的文章。 http://www.html5rocks.com/en/tutorials/cors/

【讨论】:

【参考方案3】:

使用带有 Spring MVC、Spring Security 5 和 Thymeleaf 3.0.11 的 Spring Boot 2.2.1 的替代解决方案

我很高兴终于找到了解决这个问题的方法,我也想在这里分享一下:

问题

在我的例子中,它是对返回 404 错误状态(未找到)的有效 URL 的 $.ajax POST 请求。

@Mushtaq Jameel 解释说问题的最初原因是 csrf在 Spring Security 4 中默认启用 (source)。 p>

解决方案

我还没有测试过@Mushtaq Jameel 提出的建议,但这个优雅的快速修复对我有用:

AJAX 代码:

  $.ajax(
                type: "POST",
                url: "/",
                data: $('.cd-signin-modal__form.sign-up').serialize(),  // <- FIX    
                success: // some code
                error: // some code
            );

        

换句话说,解决方案是在 HTML 表单本身上调用 .serialize() 方法。

然后发生的情况是,在 POST 请求中自动添加了一个 _csfr 令牌作为附加的表单参数:

这又是因为在较新版本的 Spring Security 中默认启用了 csrf(here 提到这个隐藏的表单参数是自动添加的)。

然后我的 Spring MVC 控制器接受如下形式:

 @PostMapping("/")
    public String createUser(@Valid @ModelAttribute User user, @Valid @ModelAttribute UserDetails userDetails, BindingResult errors) 
        if (errors.hasErrors()) 
            // handle errors
        
        //  persist objects in database
        return "index";
    

【讨论】:

【参考方案4】:

您是否尝试过使用普通的 http 请求来发布使用 spring security 您必须使用特定的变量名集,您可以用谷歌搜索它。

同时检查我们是否可以使用 AJAX 向受限 URL 发送 post 请求。

【讨论】:

@himashu - 我做得很好,而且 GET 请求似乎没有与 ajax 调用有关的问题。你说的一组特定的变量名是什么意思,你说的是 j_username 和 j_password,不是登录的那些东西吗?

以上是关于Spring Security - 所有 JQuery Ajax 发布请求都返回 404的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security - 所有 JQuery Ajax 发布请求都返回 404

Spring Security - 基于所有权的访问

非所有者时 Spring Security 更新 acl

Spring Data Rest with Spring Security - 按当前用户查找所有内容

获取 Spring Security 中的所有登录用户

Spring Security - 更改 RedirectStrategy 的所有实例