Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
defmodule ElijahWeb.EnsureRolePlug do
@moduledoc """
This plug ensures that a user has a particular role before accessing a given route.
## Example
Let's suppose we have three roles: :admin, :manager and :user.
If you want a user to have at least manager role, so admins and managers are authorised to access a given route
plug ElijahWeb.EnsureRolePlug, [:admin, :manager]
If you want to give access only to an admin:
plug ElijahWeb.EnsureRolePlug, :admin
"""
import Plug.Conn
alias Elijah.Accounts
alias Elijah.Schema.User
alias Phoenix.Controller
alias Plug.Conn
@doc false
@spec init(any()) :: any()
def init(config), do: config
@doc false
@spec call(Conn.t(), atom() | [atom()]) :: Conn.t()
def call(conn, roles) do
user_token = get_session(conn, :user_token)
(user_token &&
Accounts.get_user_by_session_token(user_token))
|> has_role?(roles)
|> maybe_halt(conn)
end
defp has_role?(%User{} = user, roles) when is_list(roles),
do: Enum.any?(roles, &has_role?(user, &1))
defp has_role?(%User{role: role}, role), do: true
defp has_role?(_user, _role), do: false
defp maybe_halt(true, conn), do: conn
defp maybe_halt(_any, conn) do
conn
|> Controller.put_flash(:error, "Unauthorised")
|> Controller.redirect(to: signed_in_path(conn))
|> halt()
end
defp signed_in_path(_conn), do: "/"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment