Skip to content

Instantly share code, notes, and snippets.

@ahey
Created February 24, 2023 06:22
Show Gist options
  • Save ahey/61238fdc367175589fa90431318705c9 to your computer and use it in GitHub Desktop.
Save ahey/61238fdc367175589fa90431318705c9 to your computer and use it in GitHub Desktop.
Ash Framework module for finding out whether an actor is allowed to perform an action on a particular resource instance
defmodule Auth do
require Ash.Query
def can_on_instance?(resource, id, action_name, actor, api) do
action = Ash.Resource.Info.action(resource, action_name)
case action.type do
:create ->
false
:read ->
query =
resource
|> Ash.Query.for_read(action_name)
strict_check(actor, id, query, api)
:update ->
changeset =
struct(resource)
|> Ash.Changeset.new(%{})
|> Ash.Changeset.for_update(action_name)
strict_check(actor, id, changeset, api)
:destroy ->
changeset =
struct(resource)
|> Ash.Changeset.new(%{})
|> Ash.Changeset.for_destroy(action_name)
strict_check(actor, id, changeset, api)
end
end
def strict_check(actor, id, %{__struct__: Ash.Query} = query, api) do
authorizer = %Ash.Policy.Authorizer{
actor: actor,
resource: query.resource,
action: query.action
}
case Ash.Policy.Authorizer.strict_check(authorizer, %{
api: api,
query: query,
changeset: nil
}) do
{:error, _error} ->
false
:authorized ->
true
{:filter, _, filter} ->
query
|> Ash.Query.filter(id == ^id)
|> Ash.Query.filter(^filter)
|> api.read_one(authorize?: false)
|> case do
{:ok, nil} -> false
{:ok, _} -> true
_ -> false
end
_ ->
:maybe
end
end
def strict_check(actor, id, %{__struct__: Ash.Changeset} = changeset, api) do
authorizer = %Ash.Policy.Authorizer{
actor: actor,
resource: changeset.resource,
action: changeset.action
}
case Ash.Policy.Authorizer.strict_check(authorizer, %{
api: api,
changeset: changeset,
query: nil
}) do
{:error, _error} ->
false
:authorized ->
true
{:filter, _, filter} ->
primary_read_action =
Ash.Resource.Info.primary_action!(changeset.resource, :read)
Ash.Query.for_read(changeset.resource, primary_read_action.name)
|> Ash.Query.filter(id == ^id)
|> Ash.Query.filter(^filter)
|> api.read_one(authorize?: false)
|> case do
{:ok, nil} -> false
{:ok, _} -> true
_ -> false
end
_ ->
false
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment