Phoenix - invald CSRF on AJAX post

时间:2016-11-14 20:28:37

标签: ajax phoenix-framework elixir-framework

我正在学习使用Phoenix框架,并且我正在尝试向控制器操作执行AJAX帖子 - 但是,我遇到了CSRF保护问题。

对于初学者,我没有使用表单 - 只想将文本从输入传递给控制器​​:

<input type="text" id="raw-input" />
<button id="send-button">Send it!</button>

<script>
$("#send-button").click(function(){
    var input = $("#raw-input").val();

    $.ajax({
        url: "/test/process",
        type: "POST",
        dataType: "json",
        beforeSend: function(xhr) {xhr.setRequestHeader("X-CSRF-Token", $("meta[name='csrf-token']").attr("content"))},
        data: {"input" : input},
        success: function(response){
            console.log(response);
        }
    });
});
</script>

控制器(不担心做任何事情input ......只是想验证一个成功的帖子!):

def process(conn, %{"input" => input}) do
    IO.puts "got it!"
end

路由器:

post "/test/process", TestController, :process

我几乎解除了来自Rails应用程序的$.ajax调用,它正常工作,但它没有在这里做的诀窍 - 运行它会返回403错误并记录(Plug.CSRFProtection.InvalidCSRFTokenError) invalid CSRF (Cross Site Request Forgery) token, make sure all requests include a valid '_csrf_token' param or 'x-csrf-token' header

有人可以提供任何指导吗?谢谢!

3 个答案:

答案 0 :(得分:14)

这是因为Phoenix默认情况下不会使用CSRF令牌创建元标记。它们仅包含在Phoenix的帮助函数生成的表单中,并且隐藏在输入中。

要在Phoenix中以编程方式获取CSRF令牌,您可以致电Plug.CSRFProtection.get_csrf_token/0。有很多方法可以将它传递给你的JS。您可以在布局中添加元标记以将其包含在每个页面中,但这可能不是非常有效,因为它将为所有页面生成。您也可以将它存储在您需要的视图中的JS变量中:

<input type="text" id="raw-input" />
<button id="send-button">Send it!</button>

<script>
$("#send-button").click(function(){
    var CSRF_TOKEN = <%= raw Poison.encode!(Plug.CSRFProtection.get_csrf_token()) %>;
    var input = $("#raw-input").val();

    $.ajax({
        url: "/test/process",
        type: "POST",
        dataType: "json",
        beforeSend: function(xhr) {
            xhr.setRequestHeader("X-CSRF-Token", CSRF_TOKEN);
        },
        data: {"input" : input},
        success: function(response){
            console.log(response);
        }
    });
});
</script>

答案 1 :(得分:5)

凤凰城已经有了助手csrf_meta_tag。像这样将其包括在布局中:

<html lang="en">
  <head>
     <%= csrf_meta_tag %>
     ...

然后像下面这样在您的js中使用它:$("meta[name='csrf-token']").attr("content")

答案 2 :(得分:-1)

如果您想跳过CSRF令牌检查(仅在开发API的情况下),则可以在第-行以下注释掉

插入:protect_from_forgery

在您各自的_web / router.ex内部