【问题标题】:phoenix invalid CSRF凤凰无效的CSRF
【发布时间】:2021-01-22 02:52:42
【问题描述】:

我正在尝试进行本地文件上传,但是当我执行 POST 请求时,我收到了invalid CSRF (Cross Site Request Forgery) token, make sure all requests include a valid '_csrf_token' param or 'x-csrf-token' header 错误

我已经尝试调用这个函数

def csrf_token(conn) do
    Plug.Conn.get_session(conn, :csrf_token)
end

我的 .html.eex :

<form action="/accounts/new/csv-validator" method="post" 
enctype="multipart/form-data">
    <input type="hidden" name="_csrf_token" value="<%= @get_csrf_token() %>">
    <input class="form-control input-bordered" id="user_photo" name="user[photo]" type="file">
</form>

预期结果:使用有效的 csrf 令牌成功执行 POST

凤凰版:v1.3.4

【问题讨论】:

  • 老实说,我认为这里没有足够的信息。我看到的唯一可疑的事情是你的第一个 sn-p "csrf_token()" 中有一个方法,然后在输入中你有 "@get_csrf_token()"。
  • 试试这个name="csrf-token" id="csrf-token" value="&lt;%= Plug.CSRFProtection.get_csrf_token() %&gt;"

标签: elixir phoenix-framework


【解决方案1】:

在 Phoenix 中 @ 是一个宏,即它是一个宏函数的名称:

@实际上是一个将@key翻译成Map.get(assigns, :key)的宏。

(https://hexdocs.pm/phoenix/templates.html)

我实际上认为那句话有错误,它应该是:

@ 实际上是将@key 转换为 Keyword.get(assigns, :key)。

assigns 来自这里:

render(conn, template, assigns)

https://hexdocs.pm/phoenix/Phoenix.Controller.html#render/3

结果,如果你这样调用render:

render(conn, "page.html", message: "hello", answer: "yello")
                          |_______________________________|
                                        ^
                                        |
                                      assigns (a keyword list)

然后在page.html 模板中,如果你写@message,那么Phoenix 会将其替换为Keyword.get(assigns, :message),其计算结果为"hello"

这应该表明在模板中写@get_csrf_token() 是无稽之谈。相反,您需要做的是这样的:

def your_action(conn, _params) do
  render(conn, "page.html", csrf: csrf_token(conn) )
end

然后,您可以在模板中编写@csrf 来插入令牌。

【讨论】:

    【解决方案2】:

    我发现@7stud 很有教育意义且很有帮助,但我没有给这个堆栈留下一个明确的解决方案;所以我想我会试一试。

    使用 Phoenix 渲染 EEx 模板时,有很多选择。在这个问题中,@Leka 似乎没有使用 Phoenix.HTML,但我会将它与其他选项一起列出。

    没有 Phoenix.HTML:

    <form method="post" action"...">
      <input type="hidden" name="_csrf_token" value="<%= Plug.CSRFProtection.get_csrf_token() %>">
      ...
    </form>
    

    Phoenix 的版本也是这样:

    <form method="post" action"...">
      <input type="hidden" name="_csrf_token" value="<%= Phoenix.Controller.get_csrf_token() %>">
      ...
    </form>
    

    使用 Phoenix.HTML,form_for 的各种形式在发布时会自动执行此操作(这是默认操作):

    <%= form_for @conn, "..." %>
      ...
    </form>
    

    我无法从问题中 100% 判断,但看起来@Leka 可能正在定义自定义 CSRF 函数。如果这样做了,只要在相应的 Phoenix View 文件中定义了该函数,就可以使用“@”宏从模板调用该函数。

    除非需要 Plug 提供的自定义代码,否则这种方法是不必要的。与@7stud 在渲染中使用 assigns 参数的方法相同。同样,不要不尊重@7stud 的回答;这可能是对他们对@Leka 试图做什么的解释的直接回应。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-30
      • 2016-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多