shi*_*ini 2 elixir phoenix-framework
我想从 if-else 语句的 else 部分调用插头。
我尝试过打电话,plug SpiderWeb.AdminAuth但接听不到ArgumentError: cannot set attribute @plugs inside function/macro.。
我也尝试过SpiderWeb.AdminAuth.call(conn),但出现错误UndefinedFunctionError at GET /user/1: function SpiderWeb.AdminAuth.call/1 is undefined or private.
我也可以在 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
Run Code Online (Sandbox Code Playgroud)
这是管理员身份验证插件:
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
Run Code Online (Sandbox Code Playgroud)
我的目标是确保只有当前经过身份验证的用户才能访问显示页面(使用自己的 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
Run Code Online (Sandbox Code Playgroud)
但我得到的是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
你几乎是对的,你只是忘了将第二个参数传递给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
Run Code Online (Sandbox Code Playgroud)
但也许,最好的选择是创建一个新的插件,“确保只有当前经过身份验证的用户才能访问显示页面(使用他们自己的 ID)或管理员”。这样您就可以重用它并将授权逻辑保留在操作之外。
| 归档时间: |
|
| 查看次数: |
1449 次 |
| 最近记录: |