Current section
Files
Jump to
Current section
Files
lib/cassette/controller.ex
defmodule Cassette.Controller do
@moduledoc """
A helper module to quickly validate roles and get the current user
To use in your controller, add as a plug restricting the actions:
```elixir
defmodule MyApp.MyController do
use MyApp.Web, :controller
use Cassette.Controller
plug :require_role!, "ADMIN" when action in [:edit, :update, :new, :create]
def update(conn, %{"id" => id}) do
something = Repo.get!(Something, id)
changeset = Something.changeset(something)
render(conn, "edit.html", something: something, changeset: changeset)
end
end
```
You can also customize how a forbidden situation is handled:
```elixir
defmodule MyApp.MyController do
use MyApp.Web, :controller
use Cassette.Controller, on_forbidden: fn(conn) ->
redirect(conn, to: "/403.html")
end
plug :require_role!("VIEWER")
def index(conn, _params) do
render(conn, "index.html")
end
end
```
You can use one of your controller functions as well:
```elixir
defmodule MyApp.MyController do
use MyApp.Web, :controller
use Cassette.Controller, on_forbidden: &MyApp.MyController.forbidden/1
plug :require_role!("VIEWER")
def index(conn, _params) do
render(conn, "index.html")
end
end
```
Or since `require_role!/2` halts the connection you may do the following for simple actions.
```elixir
defmodule MyApp.MyController do
use MyApp.Web, :controller
use Cassette.Controller
def index(conn, _params) do
conn
|> require_role!("VIEWER")
|> render("index.html")
end
end
```
You can also write your own plugs using the "softer" `has_role?/2` or `has_raw_role?/2`:
```elixir
defmodule MyApp.MyController do
use MyApp.web, :controller
use Cassette.Controller
plug :check_authorization
def index(conn, _params) do
render(conn, "index.html")
end
def check_authorization(conn, _params) do
if has_role?(conn, "viewer") do
conn
else
conn |> render("forbidden.html") |> halt
end
end
end
```
"""
alias Cassette.Plug.RequireRolePlug
alias Plug.Conn
defmacro __using__(opts \\ []) do
quote do
import Conn
import Cassette.Plug.RequireRolePlug, only: [has_role?: 3, has_raw_role?: 2]
defp __forbidden_callback__ do
unquote(opts[:on_forbidden]) ||
fn conn ->
conn |> resp(403, "Forbidden") |> halt
end
end
@doc """
Tests if the user has the role. Where role can be any of the terms accepted by any implementation of `has_role?/2`.
This will halt the connection and set the status to forbidden if authorization fails.
"""
@spec require_role!(Conn.t(), RequireRolePlug.role_param()) :: Conn.t()
def require_role!(conn, roles) do
if has_role?(conn, roles, unquote(opts)) do
conn
else
__forbidden_callback__().(conn)
end
end
@doc """
Tests if the user has the (raw) role. Where role can be any of the terms accepted by any implementation of `has_raw_role?/2`.
This will halt the connection and set the status to forbidden if authorization fails.
"""
@spec require_raw_role!(Conn.t(), RequireRolePlug.role_param()) :: Conn.t()
def require_raw_role!(conn, roles) do
if has_raw_role?(conn, roles) do
conn
else
__forbidden_callback__().(conn)
end
end
end
end
end