How apache/casbin works
1. What this repository is
Apache Casbin is a Go authorization engine, not an application server. The core runtime accepts a request like {subject, object, action} plus a policy/model definition, then decides allow/deny. Most of the repo is the library itself; examples/ and *_test.go files are there to validate and demonstrate supported access-control patterns.
2. Core enforcement pipeline
The central flow is: load a model and policy, build an enforcer, then call Enforce(...). The enforcer evaluates the request against the model’s matcher expression, consults policy records, and reduces matching policy effects into a final decision. The top-level entry points are in enforcer*.go, frontend.go, management_api.go, and rbac_api*.go.
3. Model subsystem
The model/ package represents Casbin’s PERM metamodel: request, policy, effect, matcher, assertions, and functions. It parses .conf model files, stores model sections, and provides the data structure the enforcer executes against. This is the configuration boundary that lets the same engine support ACL, RBAC, ABAC, RESTful, deny-override, and priority-based policies.
4. Policy and effect evaluation
Policy rows are matched against the request and then reduced by an effect strategy. The effector/ package contains the default policy-effect logic, while detector/ handles conflict/priority-style decision behavior. These components are the policy decision boundary: they determine how multiple matching rules become a single allow/deny outcome.
5. Matching and built-in operators
Request-policy comparisons are not limited to equality. The util/ package contains built-in operators such as key matching, glob matching, IP matching, and other helper functions used inside matcher expressions. This is how Casbin supports REST-style path matching and ABAC-style attribute predicates without hardcoding the model.
6. RBAC and role hierarchy
RBAC is isolated into rbac/ and the role-manager APIs. The default role manager builds and queries role links, including hierarchical roles and domain-aware roles. This subsystem feeds the enforcer with role relationships so policies can say “admin can read” instead of enumerating every user.
7. Persistence and adapters
Policy storage is abstracted behind persist/. Adapters load and save policy from external stores; file and string adapters are included, and the interfaces support filtered, batch, update, and contextual variants. This means policy storage is pluggable and the enforcer itself stays storage-agnostic.
8. Caching, syncing, and distributed consistency
Several enforcer variants support operational concerns around scale and consistency: enforcer_cached*.go uses in-memory policy result caching, enforcer_synced.go and persist/cache/ coordinate synchronized state, and enforcer_distributed.go plus watcher abstractions support multi-node policy propagation. The persist/watcher*.go code is the boundary for broadcasting policy changes to other instances.
9. Transactions and conflict handling
The transaction*.go files add transactional policy mutation behavior, including buffered updates and commit/conflict handling. This layer matters when policy updates must be atomic or serialized relative to concurrent authorization changes. It sits above persistence and below the management API.
10. Management APIs
management_api.go exposes the general-purpose policy administration surface: add/remove rules, load/save, query policy, and manipulate model state. rbac_api.go and rbac_api_with_domains.go are convenience layers specialized for role/user mapping. These APIs are the primary way applications mutate authorization state at runtime.
11. Contexts, sync variants, and internal boundaries
Context-aware and synchronized variants (enforcer_context.go, rbac_api_context.go, *_synced.go) adapt the same core behavior for callers that need request-scoped data or thread-safe access patterns. The repo also includes internal_api.go, ai_api.go, and frontend_old.go, which indicate compatibility and layered API evolution rather than separate products.
12. Configuration, errors, and logging
config/ parses runtime settings, constant/ holds shared constants, errors/ defines domain-specific error types, and log/ provides the logger abstraction. These packages are supporting infrastructure rather than decision logic, but they define the library’s runtime behavior and diagnostics surface.
13. Examples and validation
The large examples/ directory is effectively a catalog of supported authorization models and edge cases: ACL, RBAC, ABAC, domains/tenants, deny-override, priority, and custom matchers. The many *_test.go files exercise those modes and verify compatibility across enforcer variants, persistence modes, and role-manager behavior.
14. Architecture in one sentence
Casbin’s architecture is a layered authorization engine: model parsing and matcher evaluation at the core, role management and effect reduction around it, and pluggable persistence/synchronization/transaction layers around that core for real-world deployment needs.
Main entry points: enforcer.go Enforcer · adapter.go Persistence · frontend.go Frontend API · management_api.go Mgmt API
Components 19
Core engine
Request evaluation, model execution, and enforcement APIs.
- Enforcer · Main authorization runtime that evaluates requests against model and policy.
enforcer.go - Frontend API · Top-level façade for application-facing enforcement and administration entry points.
frontend.go - Mgmt API · Adds, removes, loads, saves, and queries policy and model state.
management_api.go - RBAC API · Convenience API for managing users, roles, and domain-aware mappings.
rbac_api.go - Model · Parses and stores request, policy, effect, matcher, and function sections.
model/model.go - Operators · Built-in key, glob, IP, and other matcher functions used in expressions.
util/builtin_operators.go
Policy logic
Effect reduction, conflict handling, and role hierarchy.
- Effector · Combines matching policy outcomes into a final allow or deny decision.
effector/effector.go - Detector · Handles priority and indeterminate-style decision behavior.
detector/detector.go - RBAC core · Role manager interfaces and hierarchy resolution for role links.
rbac/role_manager.go - Default role mgr · Default implementation that builds and queries role inheritance links.
rbac/default-role-manager/role_manager.go
Persistence
Adapters, cache, watchers, and transaction support.
- Persistence · Adapter interfaces for loading and saving policy state.
persist/adapter.go - File adapter · Built-in file-based adapter implementation.
persist/file-adapter/adapter.go - String adapter · Built-in in-memory/string-based adapter implementation.
persist/string-adapter/adapter.go - Policy cache · Caches policy data and synchronized state for faster repeated access.
persist/cache/cache.go - Watcher · Broadcasts policy changes to other enforcers or nodes.
persist/watcher.go - Transactions · Buffers updates and handles commit or conflict behavior for policy changes.
transaction.go
Support packages
Configuration, logging, errors, and shared helpers.
Connections 20
- Frontend API → Enforcer: creates/uses · Application-facing entry points delegate to the core runtime.
- Mgmt API → Persistence: loads/saves · Policy administration uses persistence adapters to read and write state.
- RBAC API → RBAC core: manages roles · RBAC helpers manipulate role links and domain mappings.
- Enforcer → Model: executes model · The enforcer evaluates requests using the parsed PERM model.
- Enforcer → Effector: reduces effects · Matching policy results are collapsed into a final decision.
- Enforcer → Detector: resolves conflicts · Priority and indeterminate behavior is handled during enforcement.
- Enforcer → RBAC core: consults roles · Role relationships are used during matcher evaluation.
- RBAC core → Default role mgr: default impl · The default role manager provides hierarchy queries.
- Model → Operators: uses functions · Matcher expressions call built-in comparison and path helpers.
- Persistence → File adapter: implements · File-backed storage is one concrete adapter.
- Persistence → String adapter: implements · String/in-memory storage is another concrete adapter.
- Persistence → Policy cache: supports · Cached and synchronized policy state sits behind the persistence layer.
- Persistence → Watcher: broadcasts · Watchers propagate policy updates to other instances.
- Transactions → Persistence: wraps · Transactional policy mutation sits above persistence.
- Mgmt API → Transactions: mutates atomically · Policy admin operations can route through transactional handling.
- Enforcer → Persistence: loads policy · Core runtime depends on adapters to obtain policy data.
- Enforcer → Policy cache: cached variants · Cached enforcers reuse synchronized policy results.
- Frontend API → Config: reads settings · Library behavior can be influenced by runtime configuration.
- Frontend API → Logger: logs · Public APIs rely on the logging abstraction for diagnostics.
- Mgmt API → Errors: returns · Administration APIs surface typed domain errors.