我遇到了类似的问题,我按照这个思路写了一个插件(注意我还在学习,所以这可能会做得更好):
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