authorization
Authorization
A policy controls which actions an admin may perform, which records they can see, and which menu entries and buttons render. The default policy allows everything, so authorization is opt-in.
The policy interface
A policy answers two questions:
method allows(Str:D $action, :$admin, :$resource, :$record --> Bool) { ... }
method scope($relation, :$admin, :$resource) { ... }allows authorizes an action. The action is one of index, show, create,
update, destroy, or the name of a custom member or collection action.
$admin is the current-admin, $resource is the registered resource, and
$record is set for record-level checks (show, edit, update, destroy, member
actions) and absent otherwise.
scope returns a restricted base relation. It is applied to the index listing
and to record lookups, so records outside the scope are neither listed nor
reachable (a lookup returns 404).
Install a policy with:
MVC::Keayl::Admin.authorize-with(MyPolicy.new);Enforcement
A forbidden action renders a 403 page. Record-level checks run after the record is loaded. The base relation is scoped before listing and before lookups.
When the policy forbids an action, its controls are hidden: menu entries (when
index is forbidden), the new button (create), row show, edit, and delete
actions, custom action buttons, and batch options.
Writing a policy
Subclass the base policy and override what you need; the base allows everything and scopes nothing.
use MVC::Keayl::Admin::Authorization::Policy;
class OwnedRecords is MVC::Keayl::Admin::Authorization::Policy {
method scope($relation, :$admin, :$resource) {
$relation.where({ owner_id => $admin.id })
}
method allows(Str:D $action, :$admin, :$resource, :$record --> Bool) {
return True without $record;
$record.read-attribute('owner_id') == $admin.id
}
}Role-based adapter
MVC::Keayl::Admin::Authorization::Role authorizes by the admin's role against a
permissions map. A * entry permits every action.
use MVC::Keayl::Admin::Authorization::Role;
MVC::Keayl::Admin.authorize-with(
MVC::Keayl::Admin::Authorization::Role.new(
permissions => {
viewer => <index show>,
editor => <index show create update>,
admin => <*>,
},
)
);By default the role is read from $admin.role. Pass role-of to extract it
differently:
MVC::Keayl::Admin::Authorization::Role.new(
permissions => %permissions,
role-of => -> $admin { $admin.account.role-name },
);