I have a small Phoenix application allowing users to login and consult their profile. I used the following simple route:
resources "/users", MyApp.UserController
But this allows every user to see the list of users via the :index
action, as well as delete or update any user.
What is the easiest way to restrict access to admins only? Should I add a check in front of every action? Or should I create a "/admin"
resource which would handle those operations? What is the recommended way?
You would use a plug in the UserController
. 0.4.x
has no ability for conditionally plug s, but you could achieve what you want with something like:
defmodule MyApp.UserController do
use Phoenix.Controller
plug :authenticate, :admin
plug :action
def index(conn, _) do
render conn, "index"
end
def create(conn, params) do
# do the creating
end
...
defp authenticate(conn, :admin) do
do_auth(conn, action_name(conn))
end
defp do_auth(conn, action) when action in [:create, :update, :destroy] do
if AdminAuth.authenticated?(conn) do
conn
else
halt conn
end
end
defp do_auth(conn, _action), do: conn
end
The changes coming soon in 0.5
will allow easier conditional plugs, i.e.:
defmodule MyApp.UserController do
use Phoenix.Controller
plug :authenticate, :admin when action in [:create, :update, :destroy]
def index(conn, _) do
render conn, "index"
end
def create(conn, params) do
# do the creating
end
...
defp authenticate(conn, :admin) do
if AdminAuth.authenticated?(conn) do
conn
else
halt conn
end
end
end
It's a good idea to keep your controllers for public/restricted access separate, so I would add an Admin.UserController
like you made reference to for the restricted functionality.
You could also define a separate pipeline for the authenticated endpoints:
defmodule MyApp.Router do
use MyApp.Web, :router
pipeline :admin do
plug :accepts, ["html"]
plug Authentication # this represents some plug that provides authentication
end
scope "/", MyApp do
pipe_through :browser
resources "/things", ThingController
end
scope "/admin", MyApp do
pipe_through :admin
resources "/admin/things", Admin.ThingsController
end
end
The admin scope is just an example, it can be anything you like, but the pipeline idea remains consistent.
This technique will keep your controllers cleaner, but is not always possible. It depends on your exact requirements.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With