你能在elixir中创建条件插件吗?

你能在elixir中创建条件插件吗?,elixir,phoenix-framework,Elixir,Phoenix Framework,我想从if-else语句的else部分调用一个plug 我尝试调用plug SpiderWeb.AdminAuth,但是我得到了ArgumentError:无法在函数/宏中设置属性@plugs。 我还尝试了SpiderWeb.AdminAuth.call(conn),但在get/user/1处出现了错误UndefinedFunctionError:function SpiderWeb.AdminAuth.call/1未定义或私有。 我也可以在else部分重写整个插件,但这违背了DRY原则 这是用

我想从if-else语句的else部分调用一个plug

我尝试调用
plug SpiderWeb.AdminAuth
,但是我得到了
ArgumentError:无法在函数/宏中设置属性@plugs。

我还尝试了
SpiderWeb.AdminAuth.call(conn)
,但在get/user/1处出现了错误
UndefinedFunctionError:function SpiderWeb.AdminAuth.call/1未定义或私有。

我也可以在else部分重写整个插件,但这违背了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
我的目标是确保只有当前经过身份验证的用户才能访问显示页面(使用自己的id)或管理员

编辑:其他尝试 我还尝试创建一个单独的虚拟函数,并尝试将该插件插入其中:

...
  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

但是相反,我在get/user/1:expected action/2处得到一个
运行时错误以返回一个Plug.Conn,所有的Plug都必须接收一个连接(Conn)并返回一个连接,get:nil
你几乎正确了,你只是忘记了将第二个参数传递给
call

模块插头是一个具有两个功能的模块:
init/1
call/2
。为了动态调用任何模块插件,您需要使用默认选项调用
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
但也许,最好的选择是创建一个新的插件,“确保只有当前经过身份验证的用户才能访问显示页面(使用自己的id)或管理员”。这样,您可以重用它,并将授权逻辑保留在操作之外