Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Graphql 苦艾酒-如何将_会话放入解析器函数?_Graphql_Elixir_Session Cookies_Phoenix Framework_Absinthe - Fatal编程技术网

Graphql 苦艾酒-如何将_会话放入解析器函数?

Graphql 苦艾酒-如何将_会话放入解析器函数?,graphql,elixir,session-cookies,phoenix-framework,absinthe,Graphql,Elixir,Session Cookies,Phoenix Framework,Absinthe,我用的是苦艾酒,有一个登录突变。当用户发送有效凭据时,我希望通过put\u session在响应中设置会话cookie 我面临的问题是无法从解析器函数中访问conn。这告诉我,我不应该从解析程序中更新连接的属性 可以用苦艾酒来做这个吗?有哪些替代解决方案?看起来有一种解决方案是: 在解析器中,将{:ok,}或{:error,}解析为正常 将从步骤1返回的resolution.value添加到模式匹配中,并更新GraphQL上下文 在发送响应之前,使用苦艾酒的功能(它可以访问GraphQL上下文和

我用的是苦艾酒,有一个登录突变。当用户发送有效凭据时,我希望通过
put\u session
在响应中设置会话cookie

我面临的问题是无法从解析器函数中访问
conn
。这告诉我,我不应该从解析程序中更新连接的属性

可以用苦艾酒来做这个吗?有哪些替代解决方案?

看起来有一种解决方案是:
  • 在解析器中,将
    {:ok,}
    {:error,}
    解析为正常
  • 将从步骤1返回的
    resolution.value
    添加到模式匹配中,并更新GraphQL上下文
  • 在发送响应之前,使用苦艾酒的功能(它可以访问GraphQL上下文和连接到
    put\u session
  • 代码示例 突变:

    mutation do
      @desc "Authenticate a user."
      field :login, :user do
        arg(:email, non_null(:string))
        arg(:password, non_null(:string))
        resolve(&Resolvers.Accounts.signin/3)
    
        middleware(fn resolution, _ ->
          case resolution.value do
            %{user: user, auth_token: auth_token} ->
              Map.update!(
                resolution,
                :context,
                &Map.merge(&1, %{auth_token: auth_token, user: user})
              )
    
            _ ->
              resolution
          end
        end)
      end
    end
    
    解析程序:

    defmodule AppWeb.Resolvers.Accounts do
      alias App.Accounts
    
      def signin(_, %{email: email, password: password}, _) do
        if user = Accounts.get_user_by_email_and_password(email, password) do
          auth_token = Accounts.generate_user_session_token(user)
          {:ok, %{user: user, auth_token: auth_token}}
        else
          {:error, "Invalid credentials."}
        end
      end
    end
    
    路由器:

    defmodule AppWeb.Router do
      use AppWeb, :router
    
      pipeline :api do
        plug(:accepts, ["json"])
        plug(:fetch_session)
      end
    
      scope "/" do
        pipe_through(:api)
    
        forward("/api", Absinthe.Plug,
          schema: AppWeb.Schema,
          before_send: {__MODULE__, :absinthe_before_send}
        )
    
        forward("/graphiql", Absinthe.Plug.GraphiQL,
          schema: AppWeb.Schema,
          before_send: {__MODULE__, :absinthe_before_send}
        )
      end
    
      def absinthe_before_send(conn, %Absinthe.Blueprint{} = blueprint) do
        if auth_token = blueprint.execution.context[:auth_token] do
          put_session(conn, :auth_token, auth_token)
        else
          conn
        end
      end
    
      def absinthe_before_send(conn, _) do
        conn
      end
    end
    
    一个解决方案似乎是:
  • 在解析器中,将
    {:ok,}
    {:error,}
    解析为正常
  • 将从步骤1返回的
    resolution.value
    添加到模式匹配中,并更新GraphQL上下文
  • 在发送响应之前,使用苦艾酒的功能(它可以访问GraphQL上下文和连接到
    put\u session
  • 代码示例 突变:

    mutation do
      @desc "Authenticate a user."
      field :login, :user do
        arg(:email, non_null(:string))
        arg(:password, non_null(:string))
        resolve(&Resolvers.Accounts.signin/3)
    
        middleware(fn resolution, _ ->
          case resolution.value do
            %{user: user, auth_token: auth_token} ->
              Map.update!(
                resolution,
                :context,
                &Map.merge(&1, %{auth_token: auth_token, user: user})
              )
    
            _ ->
              resolution
          end
        end)
      end
    end
    
    解析程序:

    defmodule AppWeb.Resolvers.Accounts do
      alias App.Accounts
    
      def signin(_, %{email: email, password: password}, _) do
        if user = Accounts.get_user_by_email_and_password(email, password) do
          auth_token = Accounts.generate_user_session_token(user)
          {:ok, %{user: user, auth_token: auth_token}}
        else
          {:error, "Invalid credentials."}
        end
      end
    end
    
    路由器:

    defmodule AppWeb.Router do
      use AppWeb, :router
    
      pipeline :api do
        plug(:accepts, ["json"])
        plug(:fetch_session)
      end
    
      scope "/" do
        pipe_through(:api)
    
        forward("/api", Absinthe.Plug,
          schema: AppWeb.Schema,
          before_send: {__MODULE__, :absinthe_before_send}
        )
    
        forward("/graphiql", Absinthe.Plug.GraphiQL,
          schema: AppWeb.Schema,
          before_send: {__MODULE__, :absinthe_before_send}
        )
      end
    
      def absinthe_before_send(conn, %Absinthe.Blueprint{} = blueprint) do
        if auth_token = blueprint.execution.context[:auth_token] do
          put_session(conn, :auth_token, auth_token)
        else
          conn
        end
      end
    
      def absinthe_before_send(conn, _) do
        conn
      end
    end
    

    不确定为什么要使用会话,不能使用承载器解决吗

    请忽略接口。:-)

    突变

      object :user_token_payload do
        field(:user, :user)
        field(:token, :string)
      end
    
      object :login_user_mutation_response, is_type_of: :login_user do
        interface(:straw_hat_mutation_response)
    
        field(:errors, list_of(:straw_hat_error))
        field(:successful, non_null(:boolean))
        field(:payload, :user_token_payload)
      end
    
    分解器

      def authenticate_user(args, _) do
        case Accounts.authenticate_user(args) do
          {:ok, user, token} -> MutationResponse.succeeded(%{user: user, token: token})
          {:error, message} -> MutationResponse.failed(StrawHat.Error.new(message))
        end
      end
    
    现在,客户机可以将该令牌与授权头一起传递,并使用插头将其拾取

    defmodule MyAppWeb.Plugs.Context do
      import Plug.Conn
      alias MyApp.Admission
    
      def init(opts), do: opts
    
      def call(conn, _) do
        case build_context(conn) do
          {:ok, context} -> put_private(conn, :absinthe, %{context: context})
          _ -> put_private(conn, :absinthe, %{context: %{}})
        end
      end
    
      @doc """
      Return the current user context based on the authorization header
      """
      def build_context(conn) do
        auth_header =
          get_req_header(conn, "authorization")
          |> List.first()
    
        if auth_header do
          "Bearer " <> token = auth_header
    
          case Admission.get_token_by_hash(token) do
            nil -> :error
            token -> {:ok, %{current_user: token.user}}
          end
        else
          :error
        end
      end
    end
    
    然后,您可以像这样在解析器中提取当前用户

      def create_note(%{input: input}, %{context: %{current_user: user}}) do
      end
    

    不确定为什么要使用会话,不能使用承载器解决吗

    请忽略接口。:-)

    突变

      object :user_token_payload do
        field(:user, :user)
        field(:token, :string)
      end
    
      object :login_user_mutation_response, is_type_of: :login_user do
        interface(:straw_hat_mutation_response)
    
        field(:errors, list_of(:straw_hat_error))
        field(:successful, non_null(:boolean))
        field(:payload, :user_token_payload)
      end
    
    分解器

      def authenticate_user(args, _) do
        case Accounts.authenticate_user(args) do
          {:ok, user, token} -> MutationResponse.succeeded(%{user: user, token: token})
          {:error, message} -> MutationResponse.failed(StrawHat.Error.new(message))
        end
      end
    
    现在,客户机可以将该令牌与授权头一起传递,并使用插头将其拾取

    defmodule MyAppWeb.Plugs.Context do
      import Plug.Conn
      alias MyApp.Admission
    
      def init(opts), do: opts
    
      def call(conn, _) do
        case build_context(conn) do
          {:ok, context} -> put_private(conn, :absinthe, %{context: context})
          _ -> put_private(conn, :absinthe, %{context: %{}})
        end
      end
    
      @doc """
      Return the current user context based on the authorization header
      """
      def build_context(conn) do
        auth_header =
          get_req_header(conn, "authorization")
          |> List.first()
    
        if auth_header do
          "Bearer " <> token = auth_header
    
          case Admission.get_token_by_hash(token) do
            nil -> :error
            token -> {:ok, %{current_user: token.user}}
          end
        else
          :error
        end
      end
    end
    
    然后,您可以像这样在解析器中提取当前用户

      def create_note(%{input: input}, %{context: %{current_user: user}}) do
      end
    

    对我来说,这似乎是一个明智的解决方案。谢谢分享,谢谢。不过,它比我希望的要复杂一些,所以我可能会将身份验证层保留在GraphQL之外(而使用REST)。谢谢分享,谢谢。不过,它比我希望的要复杂一些,因此我可能会将身份验证层保留在GraphQL之外(并改用REST)。感谢您使用承载令牌共享此替代解决方案。据我所知,使用承载令牌需要客户端将其存储在本地存储中,这可能会使应用程序面临更多XSS攻击。使用仅HTTP的cookie方法,这个问题就消失了(并引入了CSRF攻击,这是一种攻击)。感谢您使用承载令牌共享此替代解决方案。据我所知,使用承载令牌需要客户端将其存储在本地存储中,这可能会使应用程序面临更多XSS攻击。使用仅HTTP的cookie方法,这个问题就消失了(并引入了CSRF攻击,这会导致错误)。