2016-08-27 7 views
0

私は自分のものでないAPIリソースをユーザーが要求できないようにプラグを開発しようとしています。たとえば、JohnがAlexのプロフィールを更新しようとすると、そのリソースは彼のプロフィールではないので、アプリケーションは不正なエラーを投げます。私はGuardianを認証に使用していますが、それを忘れていない限り、GuardianのドキュメントはAPIを提供していません。だから私は自分でプラグを作成すると思った。カスタムエリクシールユーザーが自分以外のAPIリソースを要求しないようにするためのプラグ

しかし、私の実装では、カスタムプラグインを適用した(またはむしろ「パイプした」)すべての要求を拒否しているようです。

defmodule ExampleApp.Authorization do 
    use ExampleApp.Web, :controller 

    def init(opts \\ nil), do: opts 

    def call(conn, _opts) do 
    case Guardian.Plug.current_resource(conn) do 
     nil -> 
     conn 
     |> put_status(:unauthorized) 
     |> render(ExampleApp.SessionView, "forbidden.json", error: "Not Authorized") 
     |> halt 
     user -> 
     if user.id == conn.params["id"] do 
      conn 
     else 
      conn 
      |> put_status(:unauthorized) 
      |> render(ExampleApp.SessionView, "forbidden.json", error: "Not Authorized") 
      |> halt 
     end 
    end 
    end 
end 

だから私はconn.params["id"]user.idを比較するために、いくつかのコンソールの印刷を行ってきたとの比較は、ユーザID 要求したユーザーのIDでテストケースのために真である:以下のプラグインを参照してください。しかし、if-elseステートメントの 'else'条件が実行されているようです。かなり混乱しています。ここで

test "valid UPDATE of user at /users/:id route", %{conn: conn, id: id} do 
    conn = put conn, user_path(conn, :update, id), user: %{first_name: "bob"} 
    assert json_response(conn, 200)["first_name"] == "bob" 
end 

test "valid DELETE of user at /users/:id route", %{conn: conn, id: id} do 
    conn = delete conn, user_path(conn, :delete, id) 
    assert json_response(conn, 200) 
    refute Repo.get(User, id) 
end 

を失敗している2つのテストは、しかし、これらのエラーは、このエラーに基づいて

** (RuntimeError) expected response with status 200, got: 401, with body: 
    {"error":"Not Authorized"} 

の両方のためにスローされている、上からプラグインは「他」の条件を実行しています。ここで

がUserControllerで

ある
defmodule ExampleApp.UserController do 
    use ExampleApp.Web, :controller 

    plug Guardian.Plug.EnsureAuthenticated, handler: ExampleApp.SessionController 
    plug ExampleApp.Authorization when action in [:update, :delete] # Plug only runs for update and delete actions 

    alias ExampleApp.{Repo, User, SessionView} 

    #.... 

    def update(conn, %{"id" => id}) do 
    body = conn.params["user"] 
    changeset = 
     User 
     |> Repo.get!(id) 
     |> User.edit_changeset(body) 
    case Repo.update(changeset) do 
     {:ok, updated_user} -> 
     conn 
     |> put_status(:ok) 
     |> render(SessionView, "show.json", %{user: updated_user}) 
     {:error, _ } -> 
     conn 
     |> put_status(:bad_request) 
     |> render(SessionView, "error.json", %{error: "User could not be persisted to DB"}) 
    end 
    end 

    def delete(conn, %{"id" => id}) do 
    user = Repo.get!(User, id) 
    case Repo.delete(user) do 
     {:ok, _} -> 
     conn 
     |> put_status(:ok) 
     |> render(SessionView, "delete.json") 
     {:error, _} -> 
     conn 
     |> put_status(:bad_request) 
     |> render(SessionView, "error.json") 
    end 
    end 

end 

だから私はそれが私のプラグインの実装に関係しているという結論に来ています。私は間違っているかもしれませんが、私のコードを見てみたいと思います。認証され、許可された要求が拒否されるテストケースはなぜですか?

+1

'user.id'は整数ですか?これは動作しますか? 'Integer.to_string(user.id)== conn.params [" id "] do'? – Dogbert

+0

@Dogbert Manそれは常に最小のものです。迅速で有益な回答をいただきありがとうございます。あなたの男の小道具。 –

答えて

1

あなたがidのデフォルトタイプを変更しない限り、あなたはidの文字列表現を比較する必要がありますのでconn.params["id"]は、文字列になりながら、user.idは整数になります。

if Integer.to_string(user.id) == conn.params["id"] do 
    conn 
else 
    ... 
end 

だから私はいくつかを行ってきましたコンソール印刷を使用してuser.idconn.params["id"]を比較し、ユーザーIDが要求されたユーザーのIDであるテストケースで比較が成立するようにします。

あなたはおそらく"123"123の両方に同じことを印刷しIO.putsを、使用していました。デバッグのために印刷するときは、ほとんどの場合、デフォルト値のIO.inspectに設定してください。

関連する問題