php 实现 rbac
PHP 实现 RBAC(基于角色的访问控制)
RBAC(Role-Based Access Control)是一种常见的权限管理模型,通过角色关联权限,用户关联角色实现权限控制。以下是 PHP 实现 RBAC 的详细方法。
数据库设计
RBAC 通常需要以下核心表:
- users:用户表,存储用户信息。
- roles:角色表,存储角色信息。
- permissions:权限表,存储权限信息。
- role_user:用户与角色的关联表(多对多)。
- permission_role:角色与权限的关联表(多对多)。
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
password VARCHAR(255) NOT NULL
);
CREATE TABLE roles (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
description TEXT
);
CREATE TABLE permissions (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
description TEXT
);
CREATE TABLE role_user (
user_id INT NOT NULL,
role_id INT NOT NULL,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (role_id) REFERENCES roles(id)
);
CREATE TABLE permission_role (
role_id INT NOT NULL,
permission_id INT NOT NULL,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id),
FOREIGN KEY (permission_id) REFERENCES permissions(id)
);
实现权限检查逻辑
在 PHP 中,可以通过中间件或直接在业务逻辑中检查权限。以下是一个简单的权限检查示例:
class RBAC {
protected $db;
public function __construct(PDO $db) {
$this->db = $db;
}
// 检查用户是否有权限
public function checkPermission($userId, $permissionName) {
$stmt = $this->db->prepare("
SELECT COUNT(*)
FROM permissions p
JOIN permission_role pr ON p.id = pr.permission_id
JOIN role_user ru ON pr.role_id = ru.role_id
WHERE ru.user_id = :user_id AND p.name = :permission_name
");
$stmt->execute([
':user_id' => $userId,
':permission_name' => $permissionName
]);
return $stmt->fetchColumn() > 0;
}
// 获取用户所有角色
public function getUserRoles($userId) {
$stmt = $this->db->prepare("
SELECT r.name
FROM roles r
JOIN role_user ru ON r.id = ru.role_id
WHERE ru.user_id = :user_id
");
$stmt->execute([':user_id' => $userId]);
return $stmt->fetchAll(PDO::FETCH_COLUMN);
}
}
使用示例
在业务逻辑中调用 RBAC 检查权限:
$db = new PDO('mysql:host=localhost;dbname=rbac_demo', 'username', 'password');
$rbac = new RBAC($db);
$userId = 1;
$permissionName = 'edit_post';
if ($rbac->checkPermission($userId, $permissionName)) {
echo "用户有权限编辑文章";
} else {
echo "用户无权限编辑文章";
}
缓存优化
频繁查询数据库会影响性能,可以通过缓存用户权限提升效率:
class RBACWithCache extends RBAC {
protected $cache = [];
public function checkPermission($userId, $permissionName) {
if (!isset($this->cache[$userId])) {
$this->cache[$userId] = $this->loadUserPermissions($userId);
}
return in_array($permissionName, $this->cache[$userId]);
}
protected function loadUserPermissions($userId) {
$stmt = $this->db->prepare("
SELECT p.name
FROM permissions p
JOIN permission_role pr ON p.id = pr.permission_id
JOIN role_user ru ON pr.role_id = ru.role_id
WHERE ru.user_id = :user_id
");
$stmt->execute([':user_id' => $userId]);
return $stmt->fetchAll(PDO::FETCH_COLUMN);
}
}
集成到框架中
在 Laravel 等框架中,可以通过中间件实现 RBAC:
namespace App\Http\Middleware;
use Closure;
class CheckPermission {
public function handle($request, Closure $next, $permission) {
if (!auth()->user()->can($permission)) {
abort(403, '无权访问');
}
return $next($request);
}
}
路由中使用中间件:
Route::get('/admin', function () {
return view('admin.dashboard');
})->middleware('permission:admin_access');
以上方法提供了从数据库设计到实际代码实现的完整流程,可根据项目需求调整优化。







