Skip to content

Instantly share code, notes, and snippets.

@therealklanni
Last active April 9, 2016 22:03
Show Gist options
  • Save therealklanni/82924dd1540ab558cc2adb7e55e482be to your computer and use it in GitHub Desktop.
Save therealklanni/82924dd1540ab558cc2adb7e55e482be to your computer and use it in GitHub Desktop.
Authorized plug
defmodule Org.Plugs.Authorized do
@behaviour Plug
import Logger
import Plug.Conn
import Phoenix.Controller
def init(default), do: default
def call(%{assigns: %{current_user: current_user}} = conn, role) do
debug(role)
debug(current_user.role)
if current_user.role == role do
debug("User #{current_user.id} is authorized as a #{role}")
conn
else
debug("User #{current_user.id} is NOT authorized as a #{role}, redirecting")
conn
|> flash_and_redirect
end
end
def call(conn, _) do
debug("Unable to find current user")
conn
|> flash_and_redirect
end
defp flash_and_redirect(conn) do
conn
|> put_flash(:error, "You do not have the proper authorization to do that")
|> redirect(to: "/")
|> halt
end
end
defmodule Org.Router do
use Org.Web, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug Org.Plugs.AssignCurrentUser
end
pipeline :authenticated do
plug Org.Plugs.Authenticated
end
pipeline :auth_admin do
plug Org.Plugs.Authenticated
plug Org.Plugs.Authorized, :admin
end
pipeline :auth_member do
plug Org.Plugs.Authenticated
plug Org.Plugs.Authorized, :member
end
pipeline :api do
plug :accepts, ["json"]
end
# Scope for OAuth2 routes
scope "/auth", Org do
pipe_through :browser
get "/:provider", AuthController, :index
get "/:provider/callback", AuthController, :callback
delete "/logout", AuthController, :delete
end
# Scope for admin-only routes
scope "/", Org.Admin do
pipe_through [:browser, :auth_admin]
resources "/users", UserController, except: [:index, :show]
resources "/groups", GroupController, except: [:index, :show]
end
# Scope for authenticated-only routes (user is logged in)
scope "/", Org do
pipe_through [:browser, :authenticated]
get "/apply", PageController, :apply
get "/thanks", PageController, :thanks
resources "/users", UserController, only: [:index, :show]
end
# Scope for all other routes
scope "/", Org do
pipe_through :browser
get "/", PageController, :home
get "/signin", PageController, :signin
resources "/groups", GroupController, only: [:index, :show]
end
# Other scopes may use custom stacks.
# scope "/api", Org do
# pipe_through :api
# end
end
@DavidAntaramian
Copy link

  1. You'll probably want to add your @behaviour Plug statement at the top so that the compiler will perform compile time checks
  2. In line 8, plugs allow you to pass any type of opts that you would like, which may be beneficial to making this more flexible. You could pass an atom which is the expected role to look for, making this plug able to verify that the user has the role specified instead of having individual plugs per role.
  3. In line 9 case current_user |> Map.get(:role) do you are assuming that the key is present. As long as that's true of your schema, that's fine. And if it's always present, you can just use the accessor shortcut case current_user.role do
  4. Just a stylistic note, in line 16 you've moved the pipe to a second line. Since you're only piping once, your established convention in the rest of your file is to pipe on the same line.
  5. Another stylistic note, line 11 and line 14 may both benefit by having the user ID logged, too: debug("User ##{current_user.id} is an admin"). Just for your own debugging sanity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment