внедрение аутентификации в клиенте Elixir Phoenix Absinthe GraphIQL?

Я использую встроенный интерфейс GraphiQL в Absinthe. Следующее:

  pipeline :browser do
    plug RemoteIp, headers: ~w[x-forwarded-for], proxies: ~w[]
    plug :accepts, ["html", "json"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
  end

  scope "/graphiql" do
    pipe_through :browser # Use the default browser stack

    forward "/", Absinthe.Plug.GraphiQL,
            schema: ApiWeb.Schema,
            default_headers: {__MODULE__, :graphiql_headers},
            context: %{pubsub: ApiWeb.Endpoint}
  end

  def graphiql_headers(conn) do
    %{
      "X-CSRF-Token" => Plug.CSRFProtection.get_csrf_token(),
    }
  end

Мне нужно, чтобы конечный пользователь вставил Authentication: Bearer <JWT> в интерфейс, а затем нужно развернуть его для заголовка sub:, который содержит мой идентификатор пользователя, который мне нужно использовать в преобразователях.

Пользователь может настроить собственные заголовки, это не проблема. Если он затем выполнит запрос GraphSQL, интерфейс отправит POST-запрос в конечную точку / graphiql. Именно в этот момент я хочу вызвать несколько плагинов, которые проверяют JWT и получают информацию о пользователе.

Я думал, что могу использовать параметр default_headers, но, похоже, он вызывается только во время запросов GET.

Кажется, мне нужны разные конвейеры для GET и POST к конечной точке / graphiql, как мне этого добиться? Я, должно быть, делаю что-то не так ...

Обратите внимание, что если я использую один и тот же конвейер для GET и POST, JWT уже будет проверяться при простом посещении конечной точки в браузере, что мне не нужно.


person raarts    schedule 17.01.2018    source источник
comment
Вы нашли решения для этого, я также хочу реализовать токен CSRF. можете ли вы предоставить пример кода / репо?   -  person Vinay Pandya    schedule 30.05.2018


Ответы (1)


Да, на самом деле я сделал следующее:

  pipeline :authenticate_on_post_only do
    plug ApiWeb.Plugs.Authenticate, post_only: true
  end

  scope "/graphiql" do
    pipe_through [:browser, :authenticate_on_post_only]

    forward "/", Absinthe.Plug.GraphiQL,
            schema: ApiWeb.GraphQL,
            socket: ApiWeb.GraphQLSocket
  end

в сочетании с:

defmodule ApiWeb.Plugs.Authenticate do
  use Plug.Builder
  alias ApiWeb.Helpers.JWT

  plug Joken.Plug, verify: &JWT.verify/0, on_error: &JWT.error/2
  plug ApiWeb.Plugs.Subject
  plug Backend.Plug.Session

  def call(%Plug.Conn{method: "POST"} = conn, opts) do
    conn = super(conn, opts) # calls the above plugs
    put_private(conn, :absinthe, %{context: conn})  # for absinthe (GraphQL), for resolvers to re-use
  end
  def call(conn, opts) do
    if opts[:post_only] do
      conn
    else
      super(conn, opts) # calls the above plugs
    end
  end
end

Конечно, вы можете использовать любые собственные разъемы аутентификации вместо перечисленных мною.

У меня также был REST API в том же модуле, который я использовал следующим образом:

  scope "/v1", ApiWeb do
    pipe_through :api

    <my resources here>
  done

с конвейером api, определенным как:

  pipeline :api do
    plug :put_resp_content_type, "application/json"
    plug :accepts, ["json"]
    plug ApiWeb.Plugs.Authenticate
  end

который будет аутентифицироваться по любому типу HTTP-запроса.

person raarts    schedule 30.05.2018