如何仅为经过身份验证的用户确保路由Elixir Phoenix

时间:2017-05-07 02:12:14

标签: elixir phoenix-framework

我在我的应用程序中创建了几条路径

  scope "/", Socialistical do
    pipe_through :browser # Use the default browser stack


    get "/", UserController, :index
    get "/sign_up", UserController, :sign_up
    post "/create_user", UserController, :create
    options "/create_user", UserController, :nothing

    post "/session", SessionController, :create
    delete "/logout", SessionController, :delete

    get "/dashboard", DashboardController, :index
  end

除仪表板之外的其他路线是可供公众使用的路线。但我想仅为经过身份验证的用户保护仪表板路由。我创建了一个会话模型

defmodule Socialistical.Session do
  alias Socialistical.User

  def current_user(conn) do
    id = Plug.Conn.get_session(conn, :current_user)
    if id, do: Socialistical.Repo.get(User, id)
  end

  def logged_in?(conn), do: !!current_user(conn)
end

我想利用这两种方法来保护所有即将推出的路由,这些路线仅供真实用户使用,请帮助我。我不知道如何制作/转换为插件。

1 个答案:

答案 0 :(得分:1)

这是一个简单的例子。此示例仅处理验证登录用户。它不处理重定向到登录页面。

这是插件

defmodule Socialistical.Session do
  @behaviour Plug
  import Plug.Conn
  alias Socialistical.Accounts.User
  alias Socialistical.Repo

  def current_user(conn), do: conn.assigns[:current_user]
  def logged_in?(conn), do: !!current_user(conn)

  def init(opts \\ []) do
    # simple example to show how options can be passed
    %{error: opts[:error] || "Not authorized"}
  end

  def call(conn, opts \\ []) do
    if user = get_user(conn) do
      # we have a session so store it for latter access
      assign conn, :current_user, user
    else
      # not session
      halt_with_error conn, opts[:error]
    end
  end

  defp halt_with_error(conn, error) do
    conn
    |> send_resp(401, error)
    |> halt
  end

  defp get_user(conn) do
    case Plug.Conn.get_session(conn, "current_user") do
      nil -> nil
      id -> Repo.get(User, id)
    end
  end
end

路由器:

defmodule Socialistical.Web.Router do
  use Socialistical.Web, :router
  # ...
  pipeline :protected do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :fetch_flash
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug Socialistical.Session
  end

  scope "/", Socialistical.Web do
    pipe_through :browser # Use the default browser stack

    get "/", PageController, :index
    get "/login/:id", PageController, :login

    # just here for the example
    resources "/users", UserController
  end

  scope "/", Socialistical.Web do
    pipe_through :protected
    get "/protected", PageController, :protected
  end
end

这是一个用于测试的控制器。我添加了一个登录操作,只是为了测试它的全部工作。它仅用于演示目的,因为它不验证用户,只创建会话。

defmodule Socialistical.Web.PageController do
  use Socialistical.Web, :controller
  alias Socialistical.Accounts

  def index(conn, _params) do
    render conn, "index.html"
  end

  def protected(conn, _params) do
    render conn, "protected.html"
  end

  def login(conn, %{"id" => id}) do
    user = Accounts.get_user!(id)
    conn
    |> put_session("current_user", user.id)
    |> assign(:current_user, user)
    |> redirect(to: "/")
  end
end

我测试了它,它应该都可以工作。您应该查看Plug docs。同样,您可以查看我的身份验证包Coherence Session plug以获取更多想法。