Build a High‑Performance RBAC System in Webman with Casbin and ThinkORM
This guide walks PHP developers through designing a relational database schema and implementing a role‑based access control (RBAC) system in the Webman framework by integrating Casbin for policy enforcement and ThinkORM for elegant ORM handling, complete with configuration, model definitions, and middleware.
Overview
RBAC (Role‑Based Access Control) is a classic permission model that links users, roles, and permissions. By combining the Webman framework with the Casbin plugin and ThinkORM, PHP developers can quickly build an efficient RBAC system.
This combination yields concise code, strong maintainability, dynamic permission adjustments, and millisecond‑level response times, making it ideal for backend management systems.
Why Choose Webman + Casbin + ThinkORM?
RBAC model : Simple and efficient; users bind to roles, roles bind to permissions (menus or APIs), supporting multi‑role inheritance and data‑scope control.
Casbin (webman‑permission) : A Webman‑specific plugin that supports multiple access‑control models (ACL, RBAC, ABAC) with built‑in persistence (database) and seamless middleware integration.
ThinkORM : A lightweight ORM offering model relations, query building, and eager loading, perfectly suited for Webman’s high‑performance environment.
Webman framework : High‑performance, non‑blocking I/O with coroutine support, ideal for API services.
Database Design Details
The core tables implement a many‑to‑many relationship chain: user → role → menu → API, with Casbin rules storing the final policies.
1. sys_user
uid (bigint, primary key, AUTO_INCREMENT) – User ID
username (varchar(50)) – Username
password (varchar(255)) – Encrypted password
email (varchar(100)) – Email address
status (tinyint(1), default 1) – Status (1: enabled)
2. sys_role
id (bigint, primary key, AUTO_INCREMENT) – Role ID
name (varchar(50)) – Role name (e.g., "admin")
code (varchar(50)) – Role code (e.g., "admin")
data_scope (varchar(50), default 'all') – Data scope
status (tinyint(1), default 1) – Status (1: enabled)
3. sys_user_role (pivot)
user_id (bigint) – User ID
role_id (bigint) – Role ID
Composite primary key: (user_id, role_id)
4. sys_menu
id (bigint, primary key, AUTO_INCREMENT) – Menu ID
name (varchar(50)) – Menu name (English)
title (varchar(100)) – Menu title (Chinese)
type (tinyint(1), default 0) – 0: directory, 1: menu, 2: button
parent_id (bigint, default 0) – Parent menu ID (supports tree structure)
component (varchar(255)) – Front‑end component path
path (varchar(255)) – Route path
icon (varchar(100)) – Icon
sort (int(11), default 0) – Sort order
5. sys_role_menu (pivot)
role_id (bigint) – Role ID
menu_id (bigint) – Menu ID
6. sys_api
id (bigint, primary key, AUTO_INCREMENT) – API ID
name (varchar(50)) – API name
title (varchar(100)) – API title
path (varchar(255)) – API path (e.g., "/user/list")
type (varchar(10)) – HTTP method (e.g., "GET")
action (varchar(50)) – Action description (e.g., "read")
7. sys_menu_api (pivot)
menu_id (bigint) – Menu ID
api_id (bigint) – API ID
8. casbin_rule
id (bigint, primary key, AUTO_INCREMENT) – Rule ID
ptype (varchar(128)) – Policy type (e.g., "p")
v0 (varchar(128)) – Subject (e.g., role code "admin")
v1 (varchar(128)) – Object (e.g., "/user/list")
v2 (varchar(128)) – Action (e.g., "GET")
v3‑v5 (varchar(128)) – Optional extensions (e.g., data_scope)
Implementation Steps
Step 0 – Install Webman
Installation guide: https://www.workerman.net/doc/webman/install.html
Step 1 – Install Required Plugins
composer require -W workerman/webman-framework
composer require -W webman/think-orm
composer require -W casbin/webman-permissionRestart Webman after installation:
php start.php restartStep 1.1 – Configure ThinkORM (config/thinkorm.php)
return [
'default' => 'mysql',
'connections' => [
'mysql' => [
'type' => 'mysql',
'hostname' => env('DB_HOST', '127.0.0.1'),
'database' => env('DB_DATABASE', 'rbac_db'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'hostport' => env('DB_PORT', 3306),
'charset' => 'utf8mb4',
'prefix' => 'sys_',
],
],
];Step 1.2 – Configure Casbin (config/plugin/casbin/webman-permission/permission.php)
<?php
/**
* @desc permission.php description
*/
declare(strict_types=1);
return [
'default' => 'basic',
'log' => [
'enabled' => false,
'logger' => 'Casbin',
'path' => runtime_path() . '/logs/casbin.log',
],
'basic' => [
'model' => [
'config_type' => 'file',
'config_file_path' => config_path() . '/plugin/casbin/webman-permission/rbac_model.conf',
'config_text' => '',
],
// Use ThinkORM adapter
'adapter' => Casbin\WebmanPermission\Adapter\DatabaseAdapter::class,
'database' => [
'connection' => '',
'rules_table' => 'casbin_rule',
'rules_name' => null,
],
],
];Step 1.3 – DI Container (config/container.php)
$builder = new \DI\ContainerBuilder();
$builder->addDefinitions(config('dependence', []));
$builder->useAutowiring(true);
return $builder->build();Step 1.4 – Casbin Model Class (app/model/CasbinRule.php)
namespace app\model;
use think\Model;
class CasbinRule extends Model {
protected $table = 'casbin_rule';
public $timestamps = false;
}Step 2 – Define ThinkORM Models
Example: SysUser.php
namespace app\model;
use think\Model;
class SysUser extends Model {
protected $table = 'sys_user';
protected $pk = 'uid';
public function roles() {
return $this->belongsToMany(SysRole::class, 'sys_user_role', 'role_id', 'user_id');
}
public function getRoleCodes() {
return $this->roles()->column('code');
}
}SysRole.php (adds menus() relation) and SysMenu.php (adds apis() relation) follow the same pattern, using belongsToMany to link pivot tables.
Use eager loading to avoid N+1 queries, e.g.:
$role->with(['menus.apis'])->find($id);Step 3 – Sync Permissions to Casbin (RoleController.php)
namespace app\controller;
use support\Request;
use app\model\SysRole;
use Casbin\WebmanPermission\Permission;
class RoleController {
public function assignMenu(Request $request) {
$roleId = $request->post('roleId');
$menuIds = $request->post('menuIds', []);
$role = SysRole::find($roleId);
if (!$role) {
return response('角色不存在', 404);
}
// Sync role‑menu relations
$role->menus()->sync($menuIds);
// Clear old policies for this role
Permission::deletePermissionsForUser($role->code);
// Load menus and APIs, then add new policies
$role->load('menus.apis');
foreach ($role->menus as $menu) {
foreach ($menu->apis as $api) {
Permission::addPolicy($role->code, $api->path, $api->type);
}
}
return response('权限同步成功');
}
}Step 4 – Authorization Middleware
<?php
/**
* @desc Authorization middleware
*/
declare(strict_types=1);
namespace app\middleware;
use Casbin\Exceptions\CasbinException;
use Casbin\WebmanPermission\Permission;
use Tinywan\ExceptionHandler\Exception\ForbiddenHttpException;
use Tinywan\ExceptionHandler\Exception\UnauthorizedHttpException;
use Tinywan\Jwt\JwtToken;
use Webman\Http\Request;
use Webman\Http\Response;
use Webman\MiddlewareInterface;
class AuthorizationMiddleware implements MiddlewareInterface {
public function process(Request $request, callable $handler): Response {
$role = JwtToken::getExtendVal('role');
if (empty($role)) {
throw new UnauthorizedHttpException();
}
try {
$url = request()->path();
$action = request()->method();
if (!Permission::enforce($role, $url, strtoupper($action))) {
throw new ForbiddenHttpException();
}
} catch (CasbinException $e) {
throw new ForbiddenHttpException();
}
return $handler($request);
}
}Register the middleware globally (config/middleware.php):
return [
'' => [
app\middleware\AuthorizationMiddleware::class,
],
];Conclusion
Combining Casbin with ThinkORM in a Webman project provides a clean, highly extensible RBAC implementation that can be quickly integrated into any backend management system.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Tech Hub
Sharing cutting-edge internet technologies and practical AI resources.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
