Skip to content

RBAC

@stratal/framework provides role-based access control (RBAC) powered by Casbin. It supports role hierarchies, permission scopes, and database-backed policy storage via the ZenStack adapter.

import { Module } from 'stratal/module'
import { RbacModule } from '@stratal/framework/rbac'
@Module({
imports: [
RbacModule.forRoot({
model: MY_RBAC_MODEL,
defaultPolicies: [
['admin', 'users:*', '.*'],
['member', 'users:read', '.*'],
],
roleHierarchy: [
['super_admin', 'admin'],
['admin', 'member'],
],
}),
],
})
export class AppModule {}
OptionTypeDescription
modelstringCasbin model definition string
defaultPoliciesstring[][]Default policies seeded on initialization
roleHierarchy[string, string][]Role inheritance pairs [child, parent]

CasbinService is a request-scoped service that provides the full Casbin authorization API. It automatically knows the current user from AuthContext.

import { Transient, inject } from 'stratal/di'
import { CasbinService } from '@stratal/framework/rbac'
@Transient()
export class PermissionsService {
constructor(
@inject(CasbinService) private readonly casbin: CasbinService,
) {}
async canEditUsers(): Promise<boolean> {
return this.casbin.currentUserHasPermission('users:write', '.*')
}
}
MethodDescription
hasPermission(userId, scope, action)Check if a user has a specific permission
currentUserHasPermission(scope, action)Check the current request’s user
hasAnyPermission(userId, scopes[], action)Check if user has any of the listed permissions
currentUserHasAnyPermission(scopes[], action)Check current user for any of the permissions
MethodDescription
addRoleForUser(userId, role)Assign a role to a user
deleteRoleForUser(userId, role)Remove a role from a user
getRolesForUser(userId)Get all directly assigned roles
getImplicitRolesForUser(userId)Get all roles including inherited ones
hasRoleForUser(userId, role)Check if a user has a specific role
setRolesForUser(userId, roles[])Replace all roles for a user
getCurrentUserRoles()Get roles for the current request’s user
currentUserHasRole(role)Check if current user has a role
MethodDescription
addRoleInheritance(childRole, parentRole)Add a role inheritance relationship
deleteRoleInheritance(childRole, parentRole)Remove a role inheritance relationship
MethodDescription
deleteUser(userId)Remove all policies for a user
deleteRole(role)Remove a role and its policies
const permissions = await this.casbin.getPermissionsForUserAsCasbinJs(userId)
// Returns permissions in a format compatible with casbin.js for frontend enforcement

Role hierarchies let child roles inherit all permissions of parent roles:

RbacModule.forRoot({
model: MY_RBAC_MODEL,
roleHierarchy: [
['super_admin', 'admin'], // super_admin inherits all admin permissions
['admin', 'member'], // admin inherits all member permissions
],
})

With this hierarchy, a super_admin has the permissions of admin and member in addition to any permissions directly assigned to super_admin.

Use getImplicitRolesForUser() to see the full role chain including inherited roles.

The RbacModule uses a ZenStack database adapter for policy storage. Policies are persisted in the database and loaded into the Casbin enforcer. The CasbinEnforcerService manages the enforcer lifecycle:

  • Lazy-loads and caches the enforcer on first use
  • Seeds default policies and role hierarchies on initialization
  • Provides clearCache() to refresh the enforcer when policies change
  • Auth Guard for protecting routes with RBAC checks.
  • Auth for the authentication layer that provides user identity.
  • Guards for the core guard system.