在Elixir中解析器之后,从插头连接中读取原始内容

Pet*_*ton 5 elixir phoenix-framework plug

我需要检查发送到phoenix服务器的JSON内容的摘要。要检查消化,需要生肉。有什么方法可以比解析器更晚地在管道中访问插件中的原始内容。我想将以下摘要验证插件添加到管道的末尾,但无法确定它如何访问已发送的原始内容。

  plug Plug.Parsers,
    parsers: [:urlencoded, :json],
    pass: ["*/*"],
    json_decoder: Poison

  plug Plug.MethodOverride
  plug Plug.Head
  plug Plug.VerifyDigest
Run Code Online (Sandbox Code Playgroud)

rya*_*ter 5

复制自我的回答here。

您可以将自定义:body_reader选项传递给以Plug.Parsers缓存正文以供以后使用。

您不希望在解析器之前读取正文,而是缓存正文以便稍后从想要对其进行散列的插件中读取。

选项

:body_reader- 一个可选的替换(或包装器), Plug.Conn.read_body/2 用于提供一个函数,该函数可以在解析和丢弃原始主体之前访问它。它采用{Module, :function, [args]}(MFA)的标准格式,默认为 {Plug.Conn, :read_body, []}.

示例

有时您可能想要自定义解析器从连接中读取正文的方式。例如,您可能希望缓存正文以稍后执行验证,例如 HTTP 签名验证。这可以通过自定义正文阅读器来实现,该阅读器可以读取正文并将其存储在连接中,例如:

defmodule CacheBodyReader do
  def read_body(conn, opts) do
    {:ok, body, conn} = Plug.Conn.read_body(conn, opts)
    conn = update_in(conn.assigns[:raw_body], &[body | (&1 || [])])
    {:ok, body, conn}
  end
end
Run Code Online (Sandbox Code Playgroud)

然后可以设置为:

plug Plug.Parsers,
  parsers: [:urlencoded, :json],
  pass: ["text/*"],
  body_reader: {CacheBodyReader, :read_body, []},
  json_decoder: Jason
Run Code Online (Sandbox Code Playgroud)

它是在Plug v1.5.1中添加的。


mur*_*urb 3

我面临着类似的问题,我按照这个思路编写了一个插件(注意我仍在学习,所以这可能会做得更好):

defmodule Esch.Plugs.HMACValidator do
  import Plug.Conn

  def init(default), do: default

  def call(%Plug.Conn{req_headers: req_headers} = conn, _default) do
    hmac_code_tuple = List.keyfind(req_headers, "hmac_token", 0)
    if hmac_code_tuple do
      hmac_code = elem(hmac_code_tuple,1) |> String.downcase

      {:ok, body, conn} = read_body(conn)

      hmac_test_code = :crypto.hmac(:sha512, "secret", body) |> Base.encode16 |> String.downcase

      if hmac_test_code == hmac_code do
        params = Poison.decode!(body)
        conn
        |> assign(:authorized_api_call, true)
        |> struct(%{:body_params => params})
      else
        conn |> put_resp_content_type("text/plain") |> send_resp(401, "Not Authorized") |> halt
      end
    else
      conn
    end
  end

  def call(conn, _default) do
    conn
  end
end
Run Code Online (Sandbox Code Playgroud)

上述请求将 HMAC 签名正文与请求标头中的 HMAC 签名进行比较。

read_body当签名与预期签名匹配时,我通过在同一代码中解析 JSON 来规避该问题。conn如果请求不适合典型的 API 调用(在我的例子中没有 HMAC-header-token),则该 ection 会被传递,因此不会读取 body_params 。

endpoint.ex然后,我在插入 Plug.Parsers 之前插入上述插件。

...
plug MyApp.Plugs.HMACValidator

plug Plug.Parsers,
  parsers: [:urlencoded, :multipart, :json],
  pass: ["*/*"],
  json_decoder: Poison
...
Run Code Online (Sandbox Code Playgroud)

我从凤凰号的讨论中得到了一些启发:Way to Read Request Body As String