2017-01-06 1 views
1

Je dois vérifier le résumé du contenu JSON envoyé à un serveur Phoenix. Pour vérifier la digestion, le corps brut est nécessaire. Est-il possible d'accéder au contenu brut dans une prise plus tard dans le pipeline que les analyseurs. Je souhaite ajouter la fiche de vérification Digest suivante à la fin du pipeline, mais je ne peux pas déterminer comment elle accède au contenu brut envoyé.Lire le corps brut à partir d'une connexion enfichable après les analyseurs dans Elixir

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

    plug Plug.MethodOverride 
    plug Plug.Head 
    plug Plug.VerifyDigest 
+0

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

+0

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 –

+0

'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

Répondre

2

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