使用带有 ajax Rest 调用的 Spring CSRF 和带有 Thymeleaf 的 HTML 页面

Posted

技术标签:

【中文标题】使用带有 ajax Rest 调用的 Spring CSRF 和带有 Thymeleaf 的 HTML 页面【英文标题】:Use of Spring CSRF with ajax Rest call and HTML page with Thymeleaf 【发布时间】:2016-04-17 06:58:57 【问题描述】:

我正在使用带有 CSRF 的 Spring Security,但我的 javascript 中的一些 POST 调用出现问题。对于我的页面,我使用 Thymeleaf 和 html 5,对于对我的控制器的 Rest 调用,我使用 jQuery.ajax。 如果我像这样对我的表单使用 ajax 调用:

$(function() 
    $("#saveCarButton").click(
            function() 
                var form = $("#addCarForm");        
                $.ajax(
                    type : "POST",
                    url : form.attr("action"),
                    data : form.serialize(),
                    // all right with rest call
                    success : function(data) ...  
                    //error during rest call
                    error : function(data) 
                        window.location.href = "/500";
                    
                );
            );
);

一切正常,但是当我调用这个函数时:

jQuery.ajax(
        url : 'upload',
        type: 'POST',
        contentType: false,
        processData: false,
        data:formData,
        beforeSend:function(xhr) 
            waitingModal.showPleaseWait();
        ,  
        success: function(data,status,xhr)...
        error: function(xhr,status,e)
        
    ).complete(function() 
        //add timeout because otherwise user could see a too fast waiting modal
        setTimeout(function()
            waitingModal.hidePleaseWait();
        , 1000);
    );

我收到错误 403。 也许使用 thymeleaf 的形式,它可以正常工作,但是对于第二种类型的请求,我必须添加 CSRF 令牌。 我试过了

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

在我的html页面中我添加了

!--  -->
<meta name="_csrf" th:content="$_csrf.token"/>
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" th:content="$_csrf.headerName"/>

为什么它与表单一起工作? 使用表单时不需要添加任何内容吗? 使用浏览器的开发工具可以看到 _csrf 和 _csrf_header 是否有危险? 谢谢

【问题讨论】:

【参考方案1】:

这个解决方案对我有用Trying to use React/Ajax calls with Spring MVC and Thymeleaf

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

阿贾克斯:

var token = $('#_csrf').attr('content');
var header = $('#_csrf_header').attr('content');

$.ajax(
                        type: "POST",
                        url: url,
                        beforeSend: function(xhr) 
                            xhr.setRequestHeader(header, token);
                        ,

                        success: function(data, textStatus, jqXHR) 
                            alert(status);
                        ,
                        error: function(request, status, error) 
                            alert(status);
                        
                    );

【讨论】:

【参考方案2】:

这很可能是因为没有发送 CSRF 令牌,因此是 403。

这是解决这类问题的方法(至少对我而言)。

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);

总之,它将 CSRF 令牌附加到您通过 ajax 执行的任何发布请求。

【讨论】:

以上是关于使用带有 ajax Rest 调用的 Spring CSRF 和带有 Thymeleaf 的 HTML 页面的主要内容,如果未能解决你的问题,请参考以下文章

带有 Rest 服务的 Wicket 和 ajax

如何在 Spring Boot 中使用带有 Bearer Token 和 form-data 的 Rest Template 调用 REST Api

跨域请求阻塞 Spring REST 服务 + AJAX

Spring:在 REST 调用响应中插入 cookie

使用 SpringBoot 配置文件模拟 REST API 调用

带有ajax请求的Spring deferredresult