Reputation: 2608
I have created few routes in my application as
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
As other routes than dashboard are those which could be available to the public. But I want to secure dashboard route for authenticated user only. I have created a session model as
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
I want to utilise these 2 methods for securing all coming routes which will be available for the authentic user only, Please help me in this. I am kind unaware how could I make/convert it to plug.
Upvotes: 0
Views: 1251
Reputation: 4507
Here is a quick example. This examples only handles verifying a logged in user. It does not handle redirecting to a login page.
Here is the plug
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
And the router:
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
Here is a controller for testing. I added a login action just to test it all worked. Its only for demo purposes since it does not authenticate the user, only creates the session.
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
I tested this and it should all work. You should review the Plug docs. As well, you can look at my authentication package Coherence Session plug to get some more ideas.
Upvotes: 1