From 37985ac1cfcfbce986d0b2dcb2e9ce5a8bab6faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Gilberto=20Balsini=20Moura?= Date: Mon, 14 Sep 2020 12:08:38 -0300 Subject: [PATCH] Add authorisation plug --- lib/real_estate_web/plugs/ensure_role_plug.ex | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 lib/real_estate_web/plugs/ensure_role_plug.ex diff --git a/lib/real_estate_web/plugs/ensure_role_plug.ex b/lib/real_estate_web/plugs/ensure_role_plug.ex new file mode 100644 index 0000000..0543909 --- /dev/null +++ b/lib/real_estate_web/plugs/ensure_role_plug.ex @@ -0,0 +1,52 @@ +defmodule RealEstateWeb.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 RealEstateWeb.EnsureRolePlug, [:admin, :manager] + + If you want to give access only to an admin: + plug RealEstateWeb.EnsureRolePlug, :admin + """ + import Plug.Conn + + alias RealEstate.Accounts + alias RealEstate.Accounts.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