Minimal example
Policy definition
Policy module
defmodule MyApp.Policy do
use LetMe.Policy
object :article do
action :create do
allow role: :writer
end
end
end
Check module
defmodule MyApp.Policy.Checks do
def role(%MyApp.User{role: role}, _object, role), do: true
def role(_, _, _), do: false
end
Context 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
end
Check examples
Check without options
Policy module
object :article do
action :create do
allow :writer
end
end
Check implementation
def writer(%MyApp.User{role: :writer}, _object, _opts), do: true
def writer(_, _, _), do: false
Check with options
Policy module
object :article do
action :delete do
allow trust_level: 50
end
end
Check implementation
def trust_level(%MyApp.User{trust_level: actual_level}, _, required_level)
when actual_level >= required_level,
do: true
def trust_level(_, _, _), do: false
Check that depends on the object
Policy module
object :article do
action :update do
allow :own_resource
end
end
Check implementation
def own_resource(%MyApp.User{id: user_id}, %{user_id: user_id}, _), do: true
def own_resource(_, _, _), do: false
Rule examples
Multiple actions with the same rules
object :article do
action [:create, :update, :delete] do
allow :admin
end
end
Combine checks with AND
action :create do
allow [:two_fa_enabled, role: :writer]
end
Combine checks with OR
action :create do
allow role: :admin
allow role: :writer
end
Conditionally allow with exception
action :create do
allow :is_admin
deny :is_suspended
end
Always allow
action :read do
allow true
end
Always deny
action :read do
deny true
end
Always allow with exception
action :read do
allow true
deny :user_is_suspended
end
Add description
action :create do
desc "allows a user to create a new article"
allow role: :writer
end
Pre-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
end
Check 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}
end
With options
Policy module
object :article do
action :create do
pre_hooks {:preload_roles, force: true}
allow role: :admin
allow role: :editor
allow role: :writer
end
end
Check 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}
end
From a different module
object :article do
action :create do
pre_hooks {MyApp.Policy.Prehooks, :preload_roles, force: true}
allow role: :admin
allow role: :editor
allow role: :writer
end
end
Multiple 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
end
object :article do
action :create do
allow role: :admin
allow role: :editor
allow role: :writer
metadata :gql_exclude, true
metadata :desc_ja, "ユーザーが新しい記事を作成できるようにする"
end
end