javascript Spring Security CSRF Token 不适用于 AJAX 调用和表单在同一个 JSP 中提交

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27182081/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 07:05:26  来源:igfitidea点击:

Spring Security CSRF Token not working with AJAX call & form submit in same JSP

javascriptspring-security

提问by siva

I am trying to implement spring security (ver 3.2.3) CSRF token in my project by referring below links

我正在尝试通过参考以下链接在我的项目中实施 spring 安全(版本 3.2.3)CSRF 令牌

http://docs.spring.io/autorepo/docs/spring-security/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#csrfhttp://docs.spring.io/autorepo/docs/spring-security/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#the-csrfmetatags-tag

http://docs.spring.io/autorepo/docs/spring-security/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#csrf http://docs.spring.io/autorepo/docs/spring-security/ 4.0.0.CI-SNAPSHOT/reference/htmlsingle/#the-csrfmetatags-tag

I am able to integrate CSRF token in JSP successfully without AJAX call. But when I tried JSP with AJAX call, getting 'invalid CSRF token exception'. After my analysis I found for both AJAX call & form submission using same token due to this i am getting 'invalid CSRF token exception'.

我能够在没有 AJAX 调用的情况下成功地将 CSRF 令牌集成到 JSP 中。但是当我用 AJAX 调用尝试 JSP 时,得到“无效的 CSRF 令牌异常”。经过我的分析,我发现 AJAX 调用和表单提交都使用相同的令牌,因为我收到了“无效的 CSRF 令牌异常”。

Could please any one help me to get raid of this issue. Is there any way to to generate two tokens i.e. one for AJAX call & one for form submission

请任何人帮助我解决这个问题。有没有办法生成两个令牌,即一个用于 AJAX 调用,一个用于表单提交

security.xml

安全文件

    <access-denied-handler ref="accessDenied" />

    <intercept-url pattern="/**"  access="ROLE_1" />

    <form-login  default-target-url='/loginUser.htm' always-use-default-target='true' authentication-failure-url='/forms/common/login.jsp?error=true' />

    <logout logout-success-url="/forms/common/logout.jsp" invalidate-session="true" delete-cookies="JSESSIONID" />

    <session-management invalid-session-url="/forms/common/sessionexpired.jsp" session-authentication-error-url="/forms/common/login.jsp?Error=alreadyLoggedin" >

        <concurrency-control expired-url="/forms/common/sessionexpired.jsp" max-sessions="1" error-if-maximum-exceeded="true" />

    </session-management>

    <csrf request-matcher-ref="csrfSecurityRequestMatcher"/>
</http>

<beans:bean class="com.concerto.pg.login.security.CsrfSecurityRequestMatcher" id="csrfSecurityRequestMatcher"/> 

JSP

JSP

<head>

<sec:csrfMetaTags />

<script type="text/javascript" charset="utf-8">

function changeList(id,option){ 

    var csrfParameter = $("meta[name='_csrf_parameter']").attr("content");
    var csrfToken = $("meta[name='_csrf']").attr("content"); 

    var institution = document.getElementById("institutionId").value; 
    var data = {};

    data[csrfParameter] = csrfToken;
    data["institutionId"] = option;

 if(id=="institutionId"){

    var result ='';

               $.ajax({
                     type: "GET",
                     async: false,
                      url: './getMerchantByInstitution.htm',
                     data: data,//"institutionId=" + option,
                     dataType:'json',
                     success: function (res) {
                     result = res;     
                         var htmlVar = '';
                            for (var i=0; i<result.length; i++){
                                htmlVar += '<option 
                                value="'+result[i]+'">'+result[i]+'</option>';                              
                            }
                            htmlVar += '<option value="ALL">ALL</option>';
                             $('#merchantId').html(htmlVar);
                     }
                 }); 



    }

}

</script>
</head>
added below < input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> statement in form tag 

Thanks & Regards, Siva

感谢和问候, Siva

回答by anykey_dev

To make an AJAX/JSON request with CSRF enabled you have to pass CSRF token as a HTTP Request Header, not a parameter or other data.

要在启用 CSRF 的情况下发出 AJAX/JSON 请求,您必须将 CSRF 令牌作为 HTTP 请求标头传递,而不是参数或其他数据。

On the page, your meta tags should look like these:

在页面上,您的元标记应如下所示:

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

Then, prepare values somewhere in the JS code:

然后,在 JS 代码中的某处准备值:

var token = $("meta[name='_csrf']").attr("content");
var header = $("meta[name='_csrf_header']").attr("content");

Pass the CSRF token as a header:

将 CSRF 令牌作为标头传递:

$.ajax({
        type: "GET",
        async: false,
        url: './getMerchantByInstitution.htm',
        data: "institutionId=" + option,
        beforeSend: function(xhr) {
            // here it is
            xhr.setRequestHeader(header, token);
        },
        success: function(obj) {
            //  ....
        },
        ....

Though it's totally up to you, I'd recommend to use something like JSON.stringify to pass the data, but it depends, of course.

虽然这完全取决于你,但我建议使用类似 JSON.stringify 的东西来传递数据,但这当然取决于。

The reference is here:

参考资料在这里:

http://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/csrf.html#csrf-include-csrf-token-ajax

http://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/csrf.html#csrf-include-csrf-token-ajax

Hope this helps.

希望这可以帮助。

回答by Aeseir

I hope this below answer helps. Make these changes

我希望下面的答案有帮助。进行这些更改

var csrfParameter = $("meta[name='_csrf_parameter']").attr("content");
var csrfToken = $("meta[name='_csrf']").attr("content"); 
var csrfHeader = $("meta[name='_csrf_header']").attr("content");  // THIS WAS ADDED

and after

之后

data[csrfParameter] = csrfToken;
data["institutionId"] = option;
headers[csrfHeader] = csrfToken;    // THIS WAS ADDED

finally change in the ajax call:

最后在ajax调用中改变:

url: './getMerchantByInstitution.htm',
headers: headers,    // THIS WAS ADDED
data: data,//"institutionId=" + option,
dataType:'json',

Let me know if this works.

让我知道这个是否奏效。

回答by simonalmar

This fixed my issue for me:

这为我解决了我的问题:

<meta name="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>

using org.thymeleaf.extras:thymeleaf-extras-springsecurity4:3.0.2.RELEASE

使用 org.thymeleaf.extras:thymeleaf-extras-springsecurity4:3.0.2.RELEASE