Created
March 7, 2023 11:13
-
-
Save arjan/ea40eba4d5d8069b8b7445ca27a57f49 to your computer and use it in GitHub Desktop.
LiveView ACL check example code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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