Permit.Phoenix.LiveView.AuthorizeHook (permit_phoenix v0.3.0)
View SourceHooks into the :mount and :handle_params lifecycles to authorize the current action. The current action is denoted by the :live_action assign (retrieved from the router), for example with the following route definition:
live "/organizations", OrganizationLive.Index, :index
the :live_action assign value will be :index.
Configuration
In the router, use the :on_mount option of live_session to configure it, passing a tuple. For convenience, you might return this tuple from a function that you might import into the router.
live_session :some_session, on_mount: Permit.Phoenix.LiveView.AuthorizeHook do
live "/organizations", MyLive.Index, :index
# ...
end
Usage
Authorization is done on live view mount and in handle_params (where the URL, and hence assigns.live_action, may change).
A live view module using the authorization mechanism should mix in the LiveViewAuthorization module:
defmodule MyAppWeb.DocumentLive.Index
use Permit.Phoenix.LiveView
end
which adds the LiveViewAuthorization behavior with the following callbacks to be implemented - for example:
# The related schema
def resource_module, do: Document
# Loader function for a singular resource in appropriate actions (:show, etc.); usually a context
# function. If not defined, Repo.get is used by default.
def loader, do: fn id -> get_organization!(id) end
Depending on whether you use use MyAppWeb, :live_view
or not to configure your LiveViews,
it might be more convenient to provide configuration as options when you mix it in via use
.
For instance:
# my_app_web.ex
def live_view do
use Permit.Phoenix.LiveView,
authorization_module: Lvauth.Authorization,
fallback_path: "/unauthorized"
end
# your live view module
defmodule MyAppWeb.PageLive do
use MyAppWeb, :live_view
@impl true
def resource_module, do: MyApp.Item
# you might or might not want to override something here
@impl true
def fallback_path: "/foo"
end
In actions like :show, where a singular resource is to be authorized and preloaded, it is preloaded into the :loaded_resources assign. This way, you can implement your :handle_params event without caring about loading the record:
@impl true
def handle_params(_params, _, socket) do
{:noreply,
socket
|> assign(:page_title, page_title(socket.assigns.live_action))
|> assign(:organization, socket.assigns.loaded_resources)}
end
Optionally, a handle_unauthorized/2 optional callback can be implemented, returning {:cont, socket} or {:halt, socket}. The default implementation returns:
{:halt, push_redirect(socket, to: socket.view.fallback_path())}
Summary
Functions
@spec on_mount(term(), map(), map(), Permit.Phoenix.Types.socket()) :: Permit.Phoenix.Types.hook_outcome()