Authorization evaluates a request such as (alice, read, invoice-42, current context) and returns permit or deny. Authentication establishes that the caller is Alice; authorization still has to prove that Alice may read this invoice. Enforce that decision on every request, close to the resource, and deny when no rule matches.

The common models are not mutually exclusive. An application can use RBAC to grant coarse capabilities, ABAC to add tenant and risk conditions, and an ACL to record exceptions on one document.

Compare on the Same Axes

ModelDecision inputWho controls policyGood fitMain cost
ACLPer-resource entries such as user:alice -> readResource service or administratorA small number of shareable objectsEntries multiply across resources and become hard to audit
DACThe resource owner delegates access, often through ACLsResource ownerUser-owned files and collaborationA compromised or careless owner can grant access too broadly
MACCentrally assigned subject clearances and object classificationsCentral security authorityRegulated or military-style information flowsRigid labels make ordinary collaboration expensive
RBACUser roles mapped to permissionsRole administratorsStable job functions such as billing operator or auditorRole explosion appears when tenant, ownership, time, or risk matters
ABACSubject, resource, action, and environment attributes evaluated by policyCentral policy owners plus attribute authoritiesMulti-tenant and context-sensitive decisionsStale attributes and opaque policies make failures difficult to explain
ReBACRelationships in a graph, such as owner, member, parent, or viewerRelationship owners plus central constraintsDocuments, repositories, teams, and nested collaborationGraph traversal, caching, and relationship consistency become security boundaries

One Invoice, Three Decisions

Suppose GET /invoices/42 is requested by a signed-in billing agent.

  • RBAC can permit invoice:read for the BillingAgent role, but that alone may expose every tenant’s invoices.
  • ABAC can require user.tenant_id == invoice.tenant_id, invoice.status != "sealed", and a device risk score below the policy threshold.
  • ReBAC can permit access when the caller owns the customer account or belongs to its billing team.

The endpoint must load invoice 42 and authorize that exact object. Hiding the identifier or checking only the UI menu leaves an insecure direct object reference: changing /42 to /43 bypasses the intended boundary.

ASP.NET Core Mapping

ASP.NET Core roles are a direct RBAC tool. Policies can combine claims and custom requirements for ABAC-like checks. Resource-based authorization passes the loaded object to a handler, which is the right place for ownership and relationship decisions.

var invoice = await repository.GetAsync(invoiceId);
if (invoice is null)
    return NotFound();
 
var decision = await authorizationService.AuthorizeAsync(
    User,
    invoice,
    "CanReadInvoice");
 
return decision.Succeeded ? Ok(invoice) : Forbid();

Keep policy decisions deterministic and observable: record the policy and rule that denied a request, but do not log sensitive attributes or tokens. Test explicit allow, explicit deny, missing attributes, stale relationships, and the default-deny path. See resource-based authorization for the handler mechanics.

References