7

我需要检查发送到凤凰服务器的 JSON 内容的摘要。要检查消化,需要原始身体。有没有办法在管道中比解析器访问插件中的原始内容。我想将以下摘要验证插件添加到管道的末尾,但无法弄清楚它如何访问发送的原始内容。

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

  plug Plug.MethodOverride
  plug Plug.Head
  plug Plug.VerifyDigest
4

2 回答 2

5

从我这里的答案复制。

您可以将自定义: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

然后可以将其设置为:

plug Plug.Parsers,
  parsers: [:urlencoded, :json],
  pass: ["text/*"],
  body_reader: {CacheBodyReader, :read_body, []},
  json_decoder: Jason

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

于 2018-07-30T06:10:05.447 回答
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

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

read_body当签名与预期签名匹配时,我通过在同一代码中解析 JSON 来规避-problem。如果请求不适合典型的 API 调用(在我的情况下没有 HMAC-header-token),则通过该conn操作,因此未读取 body_params。

endpoint.ex然后我在插入 Plug.Parsers 之前插入了上面的插件。

...
plug MyApp.Plugs.HMACValidator

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

我从这个 Phoenix 问题的讨论中得到了一些灵​​感:Way to Read Request Body As String

于 2017-05-05T17:08:24.137 回答