3

我在 Absinthe 中使用内置的 GraphiQL 界面。如下:

  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: 标头打开它,其中包含我的用户 ID,我需要在解析器中使用它。

用户可以配置自定义标题,这没问题。如果他随后执行 GraphSQL 查询,接口将向 /graphiql 端点发出 POST。正是在一点上,我想调用一些插件来检查 JWT 并检索用户信息。

我以为我可以使用 default_headers 选项,但这似乎只在 GET 请求期间被调用。

看来我需要不同的管道用于 GET 和 POST 到 /graphiql 端点,我该如何实现?我一定做错了什么...

请注意,如果我对 GET 和 POST 使用相同的管道,则仅在访问浏览器中的端点时就已经检查了 JWT,这是我不想要的。

4

1 回答 1

2

是的,实际上我做了以下事情:

  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 请求进行身份验证。

于 2018-05-30T13:31:52.613 回答