Authorization
riverbase_http::casbin decides whether an authenticated principal may perform the operation a
route represents. Which rows it may touch is a separate check; see
Multi-tenancy.
Configuration
[riverbase.casbin]
enabled = true
omit_inaccessible_openapi = true # each caller sees only operations they may run
# model = """…""" # empty → the framework's default activity model
policy = """
p, todo-admin, riverbase.todo, create-todo.execute, todo, *, allow
p, todo-admin, riverbase.todo, todo.query, todo, *, allow
g, alice, todo-admin
"""
Env: RIVERBASE_CASBIN_ENABLED, RIVERBASE_CASBIN_OMIT_INACCESSIBLE_OPENAPI.
From code:
app.with_casbin_policy(POLICY_CSV);
app.with_casbin_known_roles(["todo-admin", "todo-user"]);
app.require_any_role(["todo-admin", "todo-user"]); // reject callers with none of these roles
An empty policy is deny-all.
Policy rows
p, <subject|role>, <namespace>, <activity>, <resource>, <object>, <effect>
g, <user>, <role>
| Column | Example | Notes |
|---|---|---|
| subject or role | todo-admin | A role from g, rows or the principal's roles |
| namespace | riverbase.todo | The domain |
| activity | create-todo.execute | See the mapping below |
| resource | todo | * matches any |
| object | * | An object id, or * |
| effect | allow | allow or deny |
Route-to-activity mapping
| Route | Activity |
|---|---|
POST …/{cmdkey}:post/…, POST …/{cmdkey}:exec/… | {cmdkey}.execute |
GET …/{resource}.list, .item, .meta; POST …/{report}.rept | {resource}.query |
Custom route registered with RouteAccess::Enforced | Mapped by path; unmapped paths are 403 CAS-011 |
| Custom route registered as public | Skipped, with the recorded reason and sign-off |
Startup checks
With a policy pack, startup verifies the policy against the mounted domains:
| Code | Problem |
|---|---|
CAS-011 | A route has no activity mapping |
CAS-012 | Policy and mounted routes have drifted apart |
CAS-013 | A mounted command has no policy row |
Authorizer API
To check activities off the HTTP path, for example in tests:
use riverbase_http::casbin::{build_authorizer, ActivityAuthorizer, ActivityRequest, DomainActivity};
let authz = build_authorizer(pool, None, Some(POLICY_CSV)).await?;
let activity = DomainActivity::new("riverbase.todo", "create-todo.execute").with_resource("todo");
authz.enforce(&ActivityRequest::new("alice", activity)).await?;
For commands invoked by workers, attach a CommandPolicy to the engine. See
Permissions.
Denials
A denied request returns 403 with AUT-003. That means "authenticated but not allowed," as
opposed to AUT-001 and AUT-002 for identity failures.