Canary.Hooks (canary v2.0.0-dev)
Hooks functions for loading and authorizing resources for the LiveView events.
If you want to authorize handle_params
and handle_event
LiveView callbacks
you can use mount_canary
macro to attach the hooks.
You can think about the mount_canary
as something similar to plug
but for LiveView events.
For handle_params
it uses socket.assigns.live_action
as :action
.
For handle_event
it uses the event name as :action
.
Note that the
event_name
is a string - but in Canary it's converted to an atom for consistency.
Canary.Hooks
and Canary.Plugs
are separate modules but they share the same API.
You can define plugs for standard pages and hooks for LiveView events with the same opts.
For the authorization actions, when the :required
is false (by default it's true) it might be nil.
Then the Canada.Can
implementation should be the module name of the model rather than a struct.
Example
use Canary.Hooks
mount_canary :load_and_authorize_resource,
on: [:handle_params, :handle_event],
model: Post,
only: [:show, :edit, :update]
mount_canary :authorize_resource,
on: [:handle_event],
model: Post,
only: [:my_event],
required: false
# ...
def handle_params(params, _uri, socket) do
# resource is already loaded and authorized
post = socket.assigns.post
end
def handle_event("my_event", _unsigned_params, socket) do
# Only admin is allowed to perform my_event
end
lib/abilities/user.ex
:
defimpl Canada.Can, for: User do
def can?(%User{} = user, :my_event, Post), do: user.role == "admin"
def can?(%User{id: id}, _, %Post{user_id: user_id}), do: id == user_id
end
Summary
Functions
Authorize the :current_user
for the ginve resource. If the :current_user
is not authorized it will halt the socket.
Loads and autorize resource and assigns it to the socket. When resource is required it will halt the socket if the resource is not found. If the user is not authorized it will halt the socket.
Loads the resource and assigns it to the socket. When resource is required it will halt the socket if the resource is not found.
Mount canary authorization hooks on the current module. It creates a wrapper function to handle_params and handle_event, and attaches the hooks to the Live View.
Functions
Authorize the :current_user
for the ginve resource. If the :current_user
is not authorized it will halt the socket.
For the authorization check, it uses the can?/3
function from the Canada.Can
module -
can?(subject, action, resource)
where:
- The subject is the
:current_user
from the socket assigns. The:current_user
key can be changed in theopts
or in theApplication.get_env(:canary, :current_user, :current_user)
. By default it's:current_user
. - The action for
handle_params
issocket.assigns.live_action
, forhandle_event
it uses the event name. - The resource is the loaded resource from the socket assigns or the model name if the resource is not loaded and not required.
Required opts:
:model
- Specifies the module name of the model to load resources from:on
- Specifies the LiveView lifecycle stages to attach the hook. Default :handle_params
Optional opts:
:only
- Specifies which actions to authorize:except
- Specifies which actions for which to skip authorizationFor
handle_params
it usessocket.assigns.live_action
as:action
. Forhandle_event
it uses the event name as:action
.:as
- Specifies theresource_name
to get from assigns:current_user
- Specifies the key in the socket assigns to get the current user:required
- Specifies if the resource is required, when it's not assigned in socket it will halt the socket:unauthorized_handler
- Specify a handler function to be called if the action is unauthorized
Example:
mount_canary :authorize_resource,
model: Post,
only: [:show, :edit, :update]
current_user: :current_user
mount_canary :authorize_resource,
model: Post,
as: :custom_resource_name,
except: [:new, :create],
unauthorized_handler: {ErrorHandler, :unauthorized_handler}
Loads and autorize resource and assigns it to the socket. When resource is required it will halt the socket if the resource is not found. If the user is not authorized it will halt the socket.
It combines load_resource
and authorize_resource
functions.
Required opts:
:model
- Specifies the module name of the model to load resources from:on
- Specifies the LiveView lifecycle stages to attach the hook. Default :handle_params
Optional opts:
:only
- Specifies which actions to authorize:except
- Specifies which actions for which to skip authorizationFor
handle_params
it usessocket.assigns.live_action
as:action
. Forhandle_event
it uses the event name as:action
.:as
- Specifies theresource_name
to use in assigns:current_user
- Specifies the key in the socket assigns to get the current user:preload
- Specifies association(s) to preload:id_name
- Specifies the name of the id inparams
, defaults to "id":id_field
- Specifies the name of the ID field in the database for searching :id_name value, defaults to "id".:required
- Specifies if the resource is required, when it's not found it will halt the socket, default true:not_found_handler
- Specify a handler function to be called if the resource is not found:unauthorized_handler
- Specify a handler function to be called if the action is unauthorized
Example:
mount_canary :load_and_authorize_resource,
model: Comments,
id_name: :post_id,
id_field: :post_id,
only: [:comments]
mount_canary :load_and_authorize_resource,
model: Post,
as: :custom_name,
except: [:new, :create],
preload: [:comments],
error_handler: CustomErrorHandler
Loads the resource and assigns it to the socket. When resource is required it will halt the socket if the resource is not found.
load_resource
wrapper for attached hook functions, similar to the load_resource/2
plug
but for LiveView events on :handle_params
and :handle_event
stages.
Required opts:
:model
- Specifies the module name of the model to load resources from:on
- Specifies the LiveView lifecycle stages to attach the hook. Default :handle_params
Optional opts:
:only
- Specifies which actions to authorize:except
- Specifies which actions for which to skip authorizationFor
handle_params
it usessocket.assigns.live_action
as:action
. Forhandle_event
it uses the event name as:action
.:as
- Specifies theresource_name
to use in assigns:preload
- Specifies association(s) to preload:id_name
- Specifies the name of the id inparams
, defaults to "id":id_field
- Specifies the name of the ID field in the database for searching :id_name value, defaults to "id".:required
- Specifies if the resource is required, when it's not found it will halt the socket:not_found_handler
- Specify a handler function to be called if the resource is not found
Example:
mount_canary :load_resource,
model: Post,
only: [:show, :edit, :update],
preload: [:comments]
mount_canary :load_resource,
on: [:handle_params, :handle_event]
model: Post,
as: :custom_name,
except: [:new, :create],
preload: [:comments],
not_found_handler: {ErrorHandler, :not_found_handler}
Mount canary authorization hooks on the current module. It creates a wrapper function to handle_params and handle_event, and attaches the hooks to the Live View.
Example
mount_canary :load_and_authorize_resource,
model: Post,
only: [:edit: :update]