Minimal example
Policy definition
Policy module
defmodule MyApp.Policy do
use LetMe.Policy
object :article do
action :create do
allow role: :writer
end
end
endCheck module
defmodule MyApp.Policy.Checks do
def role(%MyApp.User{role: role}, _object, role), do: true
def role(_, _, _), do: false
endContext module
defmodule MyApp.Blog do
alias MyApp.Blog.Article
alias MyApp.Policy
def create_article(params, %MyApp.User{} = current_user) do
with :ok <- Policy.authorize(:article_create, current_user) do
%Article{}
|> Article.changeset(params)
|> Repo.insert()
end
end
endCheck examples
Check without options
Policy module
object :article do
action :create do
allow :writer
end
endCheck implementation
def writer(%MyApp.User{role: :writer}, _object), do: true
def writer(_, _), do: falseA check written as a bare atom is called with two arguments.
Check with options
Policy module
object :article do
action :delete do
allow trust_level: 50
end
endCheck implementation
def trust_level(%MyApp.User{trust_level: actual_level}, _, required_level)
when actual_level >= required_level,
do: true
def trust_level(_, _, _), do: falseA check written as a {name, option} tuple is called with three arguments.
Check that depends on the object
Policy module
object :article do
action :update do
allow :own_resource
end
endCheck implementation
def own_resource(%MyApp.User{id: user_id}, %{user_id: user_id}), do: true
def own_resource(_, _), do: falseRule examples
Multiple actions with the same rules
object :article do
action [:create, :update, :delete] do
allow :admin
end
endCombine checks with AND
action :create do
allow [:two_fa_enabled, role: :writer]
endCombine checks with OR
action :create do
allow role: :admin
allow role: :writer
endConditionally allow with exception
action :create do
allow :is_admin
deny :is_suspended
endAlways allow
action :read do
allow true
endAlways deny
action :read do
deny true
endAlways allow with exception
action :read do
allow true
deny :user_is_suspended
endAdd description
action :create do
desc "allows a user to create a new article"
allow role: :writer
endPre-hooks
Without options
Policy module
object :article do
action :create do
pre_hooks :preload_roles
allow role: :admin
allow role: :editor
allow role: :writer
end
endCheck module
def role(%MyApp.User{roles: roles}, _object, role) do
Enum.any?(roles, & &1.id == role)
end
def role(_, _, _), do: false
def preload_roles(subject, object) do
{MyApp.Repo.preload(subject, [:roles]), object}
endEvery option except :error that you pass to an authorize function is appended
to the hook arguments. A hook registered without options is called with three
arguments as soon as the caller passes any option.
With options
Options are only accepted in the three-element form. The module has to be named even when the hook is in the check module.
Policy module
object :article do
action :create do
pre_hooks {MyApp.Policy.Checks, :preload_roles, force: true}
allow role: :admin
allow role: :editor
allow role: :writer
end
endCheck module
def role(%MyApp.User{roles: roles}, _object, role) do
Enum.any?(roles, & &1.id == role)
end
def role(_, _, _), do: false
def preload_roles(subject, object, opts) do
{MyApp.Repo.preload(subject, [:roles], opts), object}
endFrom a different module
object :article do
action :create do
pre_hooks {MyApp.Policy.Prehooks, :preload_roles}
allow role: :admin
allow role: :editor
allow role: :writer
end
endMultiple pre-hooks
object :article do
action :create do
pre_hooks [:preload_roles, :role_list_to_role_id_list]
allow role: :admin
allow role: :editor
allow role: :writer
end
endMetadata
object :article do
action :create do
allow role: :admin
allow role: :editor
allow role: :writer
metadata :gql_exclude, true
metadata :desc_ja, "ユーザーが新しい記事を作成できるようにする"
end
end