Skip to content

Instantly share code, notes, and snippets.

@arjan
Created March 7, 2023 11:13
Show Gist options
  • Save arjan/ea40eba4d5d8069b8b7445ca27a57f49 to your computer and use it in GitHub Desktop.
Save arjan/ea40eba4d5d8069b8b7445ca27a57f49 to your computer and use it in GitHub Desktop.
LiveView ACL check example code
defmodule ExampleApp.Web.LiveAcl do
@moduledoc """
ACL checks for LiveView
```
use ExampleApp.Web.LiveAcl
```
Provides an `on_mount` hook to do ACL checks on mount, for instance
to ensure the current user has access to a given invoice ID.
```
on_mount(ExampleApp.Web.Live.FetchUser)
on_mount({ExampleApp.Web.LiveAcl, invoice: :read)
def mount(%{"invoice_id" => invoice_id}, _session, socket) do
# only reached when logged in and invoice: :read to the invoice from the params
end
```
The modules also defines a decorator, `event_acl_check`, that can be used to enforce
an ACL check on individual LiveView `handle_event/3` clauses, like
this:
```
@decorate event_acl_check(invoice: :delete)
def handle_event("delete", %{"invoice-id" => id}, socket) do
# only reached when user has the proper permission
end
```
This modules assumes there is a `current_user` in the socket assigns.
"""
use Decorator.Define, event_acl_check: 1
import Phoenix.Component
import Phoenix.LiveView
# on_mount hook, see https://hexdocs.pm/phoenix_live_view/Phoenix.LiveView.html#on_mount/1
def on_mount(arg, params, _session, socket) do
if acl_check(arg, params, socket.assigns.current_user) == :ok do
{:cont, socket}
else
{:halt, redirect(socket, to: "/login")}
end
end
# the decorator implementation
def event_acl_check(arg, body, context) do
%{args: [_action, params, socket]} = context
quote do
user = unquote(socket).assigns.current_user
socket = unquote(socket)
params = unquote(params)
if ExampleApp.Web.LiveAcl.acl_check(unquote(arg), params, user) == :ok do
unquote(body)
else
{:noreply, socket |> put_flash(:error, "Access denied")}
end
end
end
def acl_check([{object, action}], params, user) when is_atom(object) and is_atom(action) do
# perform the actual ACL check here!
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment