Je faisais face à un problème similaire, et je l'ai écrit un plug le long des lignes de cette (note que je apprends encore si cela pourrait être fait mieux):
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
La demande ci-dessus compare un corps signé HMAC avec la signature HMAC dans un en-tête de requête.
J'ai contourné le problème read_body
en analysant le JSON dans le même code lorsque la signature correspondait à la signature attendue. L'ection conn
est passée si la requête ne correspond pas à un appel d'API typique (dans mon cas, il n'y a pas de jeton d'en-tête HMAC), ce qui laisse les body_params non lus.
Je puis branché ci-dessus Branchez endpoint.ex
juste avant le Plug.Parsers est branché
...
plug MyApp.Plugs.HMACValidator
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Poison
...
Je suis un peu d'inspiration de la discussion dans ce numéro Phoenix. Way to Read Request Body As String
Le corps semble être abandonné après Plug.Parsers.JSON est fait en l'analysant. Je pense que vous devrez copier ce module et le modifier pour stocker le corps brut, puis l'utiliser à la place de l'analyseur ': json' par défaut. – Dogbert
Si c'est vraiment le cas, il semble qu'il manque des abstractions utiles. En pensant un peu plus à ce problème, il semblerait qu'il serait logique de mettre d'abord le plug-in de vérification de vérification et ensuite de laisser le corps dans la prise afin que les parseurs puissent fonctionner normalement –
'Plug.Conn.read_body/2 'demande actuellement à l'adaptateur de lire le corps. L'adaptateur par défaut, Cowboy, lit le corps directement à partir du socket TCP sous-jacent et n'autorise aucune mise en cache. Je pense que votre approche nécessiterait des changements dans 'Plug.Conn.read_body/2'. – Dogbert