Можете ли вы создать условные пробки в эликсире? - PullRequest
1 голос
/ 28 мая 2019

Я хочу вызвать штекер из части else оператора if-else.

Я пытался вызвать plug SpiderWeb.AdminAuth, но я получил ArgumentError: cannot set attribute @plugs inside function/macro..

I 'мы также попробовали SpiderWeb.AdminAuth.call(conn), но я получаю ошибку UndefinedFunctionError at GET /user/1: function SpiderWeb.AdminAuth.call/1 is undefined or private.

Я мог бы альтернативно переписать весь плагин в другой части, но это идет вразрез с принципом DRY.

Это файл контроллера пользователя:

defmodule SpiderWeb.UserController do
  use SpiderWeb, :controller

  alias Spider.Accounts
  plug :user_authenticate when action in [:index, :show]
  plug SpiderWeb.AdminAuth when action in [:index]

  ## Action parameters changed to ensure only current user has access or admin ##
  def action(conn, _) do
    args = [conn, conn.params, conn.assigns.current_user]
    apply(__MODULE__, action_name(conn), args)
  end

  def index(conn, _params) do
    users = Accounts.list_users
    render(conn, "index.html", users: users)
  end

  def show(conn, %{"id" => id}, current_user) do
    if current_user.id == String.to_integer(id) do
      user = Accounts.get_user!(id)
      render(conn, "show.html", user: user)
    else
      SpiderWeb.AdminAuth.call(conn)
    end
  end
end

Это плагин аутентификации администратора:

defmodule SpiderWeb.AdminAuth do
    import Plug.Conn
    import Phoenix.Controller

    alias Spider.Accounts
    alias SpiderWeb.Router.Helpers, as: Routes

    def init(opts), do: opts

    def call(conn, _opts) do
        case Accounts.check_admin(conn.assigns.current_user) do
            {:ok, _} -> conn
            {:error, _} -> conn
                |> put_flash(:error, "You don't have access to that page")
                |> redirect(to: Routes.page_path(conn, :index))
                |> halt()
        end  
    end
end

Моя цель - обеспечить, чтобы только текущий аутентифицированный пользователь имел доступ к странице шоу (со своим собственным идентификатором) ИЛИ администратор.

РЕДАКТИРОВАТЬ: Другие попытки Я также попытался создать отдельную фиктивную функцию и подключить к ней штекер:

...
  plug SpiderWeb.AdminAuth when action in [:index, :do_nothing]
...
def show(conn, %{"id" => id}, current_user) do
    ...
    else
      do_nothing(conn)
    end
  end

  defp do_nothing(conn) do
  end
end

Но вместо этого я получаюRuntimeError at GET /user/1 : expected action/2 to return a Plug.Conn, all plugs must receive a connection (conn) and return a connection, got: nil

1 Ответ

1 голос
/ 28 мая 2019

Вы поняли это почти правильно, вы только забыли передать второй аргумент call!

Модуль plug - это модуль с двумя функциями: init/1 и call/2.Чтобы динамически вызывать любой модуль plug, вам нужно вызвать init/1 с параметрами по умолчанию и передать call/2 с подключением в качестве первого аргумента и результатом вызова init/1 в качестве второго.Это вся спецификация штекера.:)

Другими словами, вы можете сделать это:

def show(conn, %{"id" => id}, current_user) do
  if ... do
    ...
  else
    SpiderWeb.AdminAuth.call(conn, SpiderWeb.AdminAuth.init([]))
  end
end

Но, возможно, лучший вариант для вас - создать новый плагин, который "гарантирует, что только текущий аутентифицированный пользователь сможетполучить доступ к странице шоу (с их собственным идентификатором) ИЛИ администратору ".Таким образом, вы можете использовать его повторно и сохранить логику авторизации вне действия.

...