AccessVoter
Represents an independent access control voter that evaluates authorization requests and votes allow, deny, or abstain based on specific criteria. Inspired by Symfony's Voter pattern and Spring Security's AccessDecisionVoter, this entity enables modular, composable authorization logic where different voters check different aspects of an access request (permissions, ownership, business rules, time restrictions, IP location, etc.). Each voter is responsible for one authorization concern and votes based on its evaluation. Multiple voters can be combined using an AccessDecisionStrategy to reach a final decision. Voters support different evaluation types including permission-based (checking user permissions), ownership-based (checking if user owns the resource), attribute-based (evaluating user/resource attributes), rule-based (custom business logic), and time-based (checking access windows). The entity enables separation of authorization concerns, testable access control logic, and flexible security policies across enterprise applications and multi-tenant platforms.
Properties
| Property | Type | Mode | Description | Required |
|---|---|---|---|---|
| name | string | stored | Unique identifier for the voter Example: | Required |
| label | string | stored | Human-readable display name for the voter Example: | Required |
| description | string | stored | Detailed explanation of what this voter checks and when it votes Example: | Optional |
| voterType | string | stored | Type of authorization check this voter performs Values: Example: | Required |
| priority | number | stored | Priority order for voter execution (lower number = higher priority, executed first) Example: | Required |
| isEnabled | boolean | stored | Whether this voter is currently active and participating in access decisions Example: | Required |
| supportedEntities | string[] | stored | Entity types this voter can evaluate (empty means all entities) Example: | Optional |
| supportedActions | PermissionAction[] | stored | Actions this voter can evaluate (empty means all actions) | Optional |
| configuration | json | stored | Voter-specific configuration (evaluation rules, attribute mappings, business logic parameters) Example: | Optional |
| metadata | json | stored | Additional voter metadata | Optional |
Examples
Example 1
{
"@type": "AccessVoter",
"name": "permission-voter",
"label": "Permission-Based Voter",
"description": "Checks if user has required permission via UserPermission. Votes ALLOW if permission found and active, ABSTAIN otherwise.",
"voterType": "permission-based",
"priority": 100,
"isEnabled": true,
"configuration": {
"checkExpiration": true,
"checkTenantScope": true
}
}Example 2
{
"@type": "AccessVoter",
"name": "ownership-voter",
"label": "Resource Ownership Voter",
"description": "Checks if user owns or created the resource. Votes ALLOW if user is owner, ABSTAIN otherwise.",
"voterType": "ownership-based",
"priority": 200,
"isEnabled": true,
"supportedEntities": [
"reports",
"documents",
"projects"
],
"configuration": {
"ownershipField": "createdBy"
}
}Example 3
{
"@type": "AccessVoter",
"name": "business-hours-voter",
"label": "Business Hours Voter",
"description": "Checks if access is during allowed business hours. Votes DENY if outside hours, ABSTAIN if during hours.",
"voterType": "time-based",
"priority": 50,
"isEnabled": true,
"configuration": {
"allowedHours": "09:00-17:00",
"allowedDays": [
"monday",
"tuesday",
"wednesday",
"thursday",
"friday"
],
"timezone": "America/New_York"
}
}Example 4
{
"@type": "AccessVoter",
"name": "ip-whitelist-voter",
"label": "IP Whitelist Voter",
"description": "Checks if request comes from whitelisted IP. Votes DENY if not whitelisted, ABSTAIN if whitelisted.",
"voterType": "location-based",
"priority": 10,
"isEnabled": true,
"configuration": {
"requireWhitelist": true,
"checkTenantWhitelist": true
}
}Example 5
{
"@type": "AccessVoter",
"name": "tenant-membership-voter",
"label": "Tenant Membership Voter",
"description": "Checks if user is active member of the tenant. Votes DENY if not member or inactive, ABSTAIN if active member.",
"voterType": "tenant-based",
"priority": 20,
"isEnabled": true,
"configuration": {
"requireActiveStatus": true,
"checkTenantSubscription": true
}
}Example 6
{
"@type": "AccessVoter",
"name": "custom-approval-voter",
"label": "Approval Workflow Voter",
"description": "Checks custom business rules for approval workflows. Votes based on approval state, hierarchy, and delegation rules.",
"voterType": "custom",
"priority": 300,
"isEnabled": true,
"supportedEntities": [
"invoices",
"purchase-orders"
],
"supportedActions": [
{
"@type": "PermissionAction",
"name": "approve"
}
],
"configuration": {
"requireManagerApproval": true,
"amountThreshold": 10000,
"allowDelegation": true
}
}