如何在Elixir / Phoenix

时间:2016-08-25 07:32:10

标签: authentication elixir phoenix-framework

我想从服务器端找出当前用户。 user_controller模块显示如何返回current_user以响应客户端请求。但是我很难从服务器上的另一个模块中找到如何做到这一点。

以下是我尝试但失败并出现以下错误。基本上我复制了user_controller.ex中的Guardian.Plug代码块。

正确的方法是什么?

(CompileError) web/GraphQLSession.ex:9: undefined function put_status/2                                                                                                                          
    (stdlib) lists.erl:1337: :lists.foreach/2                                                                                                                                                       
    (stdlib) erl_eval.erl:669: :erl_eval.do_apply/6     

defmodule App.GraphQLSession do
  use Guardian.Hooks

  def root_eval(_conn) do
  current_user = 
   case Guardian.Plug.current_resource(_conn) do
    nil -> 
      _conn
      |> put_status(:not_found)
      |> render(App.V1.SessionView, "error.json", error: "User not found")
    user ->
      _conn
      |> put_status(:ok)
      |> render("show.json", user: user)
   end

       %{author: current_user}
  end
end

<<<<< router.ex>>>>

defmodule App.Router do
  use App.Web, :router
  ...
  pipeline :api do
    plug :accepts, ["json"]
    plug Guardian.Plug.VerifyHeader
    plug Guardian.Plug.LoadResource

    end

  scope "/graphql" do
    pipe_through :api
    forward "/", GraphQL.Plug, [schema: {App.PublicSchema, :schema}, root_value: {App.GraphQLSession, :root_eval} ]
  end

<<<< user_controller.ex>> ....这显示了客户端如何通过控制器检索current_user。

defmodule App.V1.UserController do

  use App.Web, :controller

  alias App.User
 plug Guardian.Plug.EnsureAuthenticated, on_failure: { App.V1.SessionController, :unauthenticated_api }

  plug :scrub_params, "user" when action in [:create, :update]

def current_user(conn, %{"jwt" => jwt}) do

    case Guardian.Plug.current_resource(conn) do

      nil -> 
        conn
        |> put_status(:not_found)
        |> render(App.V1.SessionView, "error.json", error: "User not found")
      user ->
        conn
        |> put_status(:ok)
        |> render("show.json", user: user)
    end

更新:导入Plug.Conn并将_conn更改为conn后,根据David Sulc的建议,我得到的下一个错误如下:

[error] #PID<0.1026.0> running App.Endpoint terminated                                                                                                                                              
Server: localhost:4000 (http)                                                                                                                                                                               
Request: POST /graphql                                                                                                                                                                                      
** (exit) an exception was raised:                                                                                                                                                                          
    ** (Protocol.UndefinedError) protocol Enumerable not implemented for %Plug.Conn{adapter: {Plug.Adapters.Cowboy.Conn, :...}, assigns: %{error: "User not found", guardian_default_resource: nil, layout: 
false}, before_send: [#Function<1.34093945/1 in Plug.Logger.call/2>, #Function<0.30221299/1 in Phoenix.LiveReloader.before_send_inject_reloader/1>], body_params: %{"query" => "mutation CreateMutation(
$input_0:CreateInput!){createQ(input:$input_0){clientMutationId,...F3}} fragment F0 on ...}
}}, cookies: %Plug.Conn.Unfetched{aspect: :cookies}, halted: false, host: "localhost", method: "POST", owner: #PID<0.1026.0>, params: %{"query" => "mutation ....}}}, path_info: [], peer: {{1
27, 0, 0, 1}, 50944}, port: 4000, private: %{App.Router => {[], %{GraphQL.Plug => []}}, :phoenix_endpoint => App.Endpoint, :phoenix_format => "json", :phoenix_pipelines => [:api], :phoenix_route => #Funct
ion<0.58758354/1 in App.Router.match_route/4>, :phoenix_router => App.Router, :phoenix_template => "error.json", :phoenix_view => App.V1.SessionView, :plug_session_fetch => #Function<0.29336444/1 in Plug.
Session.fetch_session/1>}, query_params: %{}, query_string: "", remote_ip: {127, 0, 0, 1}, req_cookies: %Plug.Conn.Unfetched{aspect: :cookies}, req_headers: [{"host", "localhost:4000"}, {"connection", "ke
ep-alive"}, {"content-length", "632"}, {"accept", "*/*"}, {"origin", "http://localhost:4000"}, {"user-agent", "}, {"content-type", "application/json"}, {"referer", "http://localhost:4000/"}, {"accept-encoding", "gzip, deflate"}, {"accept-language", "en-US,en;q=0.8,ko;q=0.6,zh-CN;q=0.4"
}, {"alexatoolbar-alx_ns_ph", "AlexaToolbar/alx-4.0"}], request_path: "/graphql", resp_body: nil, resp_cookies: %{}, resp_headers: [{"content-type", "application/json; charset=utf-8"}, {"cache-control", "
max-age=0, private, must-revalidate"}, {"x-request-id", "ikh03v5kqightov3npgl8bv0do5rv77d"}, {"access-control-allow-origin", "*"}, {"access-control-expose-headers", ""}, {"access-control-allow-credentials
", "true"}], scheme: :http, script_name: ["graphql"], secret_key_base: "x4K=====-00-----lksMUX", state: :sent, status: 404}                                       
        (elixir) lib/enum.ex:1: Enumerable.impl_for!/1                                                                                                                                                      
        (elixir) lib/enum.ex:116: Enumerable.reduce/3                                                                                                                                                       
        (elixir) lib/enum.ex:1477: Enum.reduce/3                                                                                                                                                            
        (elixir) lib/enum.ex:1092: Enum.map/2                                                                                                                                                               
        (rethinkdb) lib/rethinkdb/query/macros.ex:93: RethinkDB.Query.Macros.wrap/1                                                                                                                         
        (rethinkdb) lib/rethinkdb/query/macros.ex:94: anonymous fn/1 in RethinkDB.Query.Macros.wrap/1                                                                                                       
        (elixir) lib/enum.ex:1092: anonymous fn/3 in Enum.map/2                                                                                                                                             
        (stdlib) lists.erl:1262: :lists.foldl/3  

2 个答案:

答案 0 :(得分:1)

我自己正在学习Elixir,但希望这会对你有帮助......

Elixir抱怨,因为控制器为您导入Plug模块(通过use App.Web, :controller)。在您定义的模块中不是这种情况,因此您需要自己导入它(参见第2行)。

另外,请注意,如果对于要忽略的变量(因此未使用),带有下划线的变量前面的命名约定。由于您的代码使用conn参数,因此不应将其匹配为_conn

defmodule App.GraphQLSession do
  import Plug.Conn, only: [put_status: 2]

  def root_eval(conn) do
    current_user = 
      case Guardian.Plug.current_resource(conn) do
        nil -> 
          conn
          |> put_status(:not_found)
          |> render(App.V1.SessionView, "error.json", error: "User not found")
        user ->
          conn
          |> put_status(:ok)
          |> render("show.json", user: user)
       end

       %{author: current_user}
  end
end

答案 1 :(得分:0)

要回答您更新的问题,您应该注意以下几点:

  1. 您的主要错误是您尝试为不支持它的内容实施Enumerable协议。请参阅以下行:** (Protocol.UndefinedError) protocol Enumerable not implemented。检查使用Enum.*模块的任何代码。确保您传入函数的任何内容都是可枚举的。
  2. 此外,Guardian无法找到您要检索的用户。在堆栈跟踪中,您可以看到:assigns: %{error: "User not found", guardian_default_resource: nil。尝试使用Guardian提供的api_sign_in功能。您可以找到更多information here。然后你应该可以使用Guardian.Plug.current_resource(conn)