Session 如何在插件中设置会话和CSRF保护?

Session 如何在插件中设置会话和CSRF保护?,session,csrf,session-management,elixir,Session,Csrf,Session Management,Elixir,我目前正在学习长生不老药,尝试制作一个小型插件项目。除了会话和CSRF保护之外,大部分都可以正常工作。当我发出GET请求时,我在Firefox或HTTPie中看不到任何会话cookie,而当我发出POST请求时,我得到一个500错误(但记录器是静默的) 这是我当前的路由器代码: defmodule ElxSimpleApi.Web do require Logger use Plug.Router import Plug.Conn alias ElxSimpleApi.{Mo

我目前正在学习长生不老药,尝试制作一个小型插件项目。除了会话和CSRF保护之外,大部分都可以正常工作。当我发出GET请求时,我在Firefox或HTTPie中看不到任何会话cookie,而当我发出POST请求时,我得到一个500错误(但记录器是静默的)

这是我当前的路由器代码:

defmodule ElxSimpleApi.Web do
  require Logger

  use Plug.Router
  import Plug.Conn

  alias ElxSimpleApi.{Models, Repo}

  plug Plug.Logger, log: :debug
  plug Plug.Parsers, parsers: [:urlencoded, :json],
    pass: ["text/*", "application/json"],
    json_decoder: Poison

  plug :put_secret_key_base

  plug Plug.Session, store: :cookie,
    key: "_elx_simple_api_session",
    encryption_salt: "elxsimpleapienc",
    signing_salt: "elxsimpleapisign",
    log: :debug
  plug :fetch_session
  plug Plug.CSRFProtection


  plug :match
  plug :dispatch

  # A bunch of routes here, omitted for clarity

  match _ do
    send_resp(conn, 404, "oops")
  end

  defp fetch_person(:int, id), do: Models.Person |> Repo.get(id)
  defp fetch_person(:str, sid), do: fetch_person(:int, String.to_integer(sid))

  defp ecto_to_map(struct) do
    struct |> Map.from_struct |> Map.drop([:__meta__])
  end

  defp put_secret_key_base(conn, _) do
    put_in conn.secret_key_base, "d5b2hHZGsUfcYB8lImcxooaLfVBlB5bg/z9a99jjHuXTvt7yb5neykHrYEjuNFnD"
  end
end
请告诉我我做错了什么。谢谢大家!


更新:感谢@josé-valim的建议,我现在知道500错误是由于无效的CSRF令牌造成的。但是cookie仍然没有被设置。

显然,问题与Plug有关。CSRFProtection不会自动将CSRF令牌放入会话,Plug.session在放入某个内容之前不会实际创建会话

我必须添加这个插件(就在
plug-plug.CSRFProtection
之后):


如果您想获得csrf_令牌,最好使用
Plug.CSRFProtection.get\u csrf\u token()
不要点击
进程。直接获取

当前,如果启用了csrf保护(
protect\u from\u fackery
),则默认情况下会将令牌设置到会话字段
“\u csrf\u token”
。可以配置字段的名称

如果您创建了自己的会话存储(
@behavior Plug.session.store
),并且希望进行csrf\u保护工作,那么您需要自己在自定义会话存储中处理
“\u csrf\u令牌”

我还添加了一个类似于

defp put_csrf_token_in_session(conn, _) do
    conn
    |> Plug.Conn.put_req_header("x-csrf-token", Plug.CSRFProtection.get_csrf_token)
    |> put_session("_csrf_token", Process.get(:plug_unmasked_csrf_token))
  end

尝试在
使用Plug.Router
之后添加
使用Plug.Debugger
,看看添加调试器是否会为您提供正确的堆栈跟踪、日志记录和所有内容。很高兴您找到了答案。如果有任何改进文档的地方,请发送PR!老实说,我认为Plug.CSRFProtection本身在这方面可以改进。当我有时间的时候,我会尝试做一个公关,尽管我对长生不老药很陌生。
defp put_csrf_token_in_session(conn, _) do
    conn
    |> Plug.Conn.put_req_header("x-csrf-token", Plug.CSRFProtection.get_csrf_token)
    |> put_session("_csrf_token", Process.get(:plug_unmasked_csrf_token))
  end