php rbac实现
PHP RBAC 实现方法
基于数据库的设计
RBAC(基于角色的访问控制)通常涉及用户、角色、权限三个核心表。以下是一个基础数据库结构设计:
用户表(users):
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE,
password VARCHAR(255)
);
角色表(roles):
CREATE TABLE roles (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) UNIQUE,
description TEXT
);
权限表(permissions):
CREATE TABLE permissions (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) UNIQUE,
description TEXT
);
用户角色关联表(user_roles):
CREATE TABLE user_roles (
user_id INT,
role_id INT,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (role_id) REFERENCES roles(id)
);
角色权限关联表(role_permissions):
CREATE TABLE role_permissions (
role_id INT,
permission_id INT,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id),
FOREIGN KEY (permission_id) REFERENCES permissions(id)
);
核心功能实现
创建RBAC服务类,封装权限检查逻辑:
class RBAC {
private $db;
public function __construct(PDO $db) {
$this->db = $db;
}
public function userHasPermission($userId, $permissionName) {
$stmt = $this->db->prepare("
SELECT COUNT(*)
FROM role_permissions rp
JOIN permissions p ON rp.permission_id = p.id
JOIN user_roles ur ON rp.role_id = ur.role_id
WHERE ur.user_id = :userId AND p.name = :permissionName
");
$stmt->execute([
':userId' => $userId,
':permissionName' => $permissionName
]);
return $stmt->fetchColumn() > 0;
}
public function assignRoleToUser($userId, $roleId) {
$stmt = $this->db->prepare("
INSERT INTO user_roles (user_id, role_id)
VALUES (:userId, :roleId)
");
return $stmt->execute([
':userId' => $userId,
':roleId' => $roleId
]);
}
}
中间件实现
创建权限检查中间件,用于保护路由:
class PermissionMiddleware {
protected $rbac;
protected $permission;
public function __construct(RBAC $rbac, $permission) {
$this->rbac = $rbac;
$this->permission = $permission;
}
public function __invoke($request, $response, $next) {
$userId = $_SESSION['user_id'] ?? null;
if (!$userId || !$this->rbac->userHasPermission($userId, $this->permission)) {
return $response->withStatus(403)->write('Forbidden');
}
return $next($request, $response);
}
}
缓存优化
为提高性能,可以实现权限缓存:
class CachedRBAC extends RBAC {
private $cache = [];
public function userHasPermission($userId, $permissionName) {
$cacheKey = "user_{$userId}_perm_{$permissionName}";
if (!isset($this->cache[$cacheKey])) {
$this->cache[$cacheKey] = parent::userHasPermission($userId, $permissionName);
}
return $this->cache[$cacheKey];
}
}
实际应用示例
在控制器中使用RBAC检查:
$app->get('/admin', function ($request, $response) {
$rbac = new RBAC($this->db);
if (!$rbac->userHasPermission($_SESSION['user_id'], 'admin_access')) {
return $response->withStatus(403);
}
return $this->view->render($response, 'admin.twig');
});
现有框架集成
对于Laravel等现代框架,可直接使用内置Gate和Policy系统:
// 在AuthServiceProvider中定义权限
Gate::define('edit-post', function ($user, $post) {
return $user->id === $post->user_id;
});
// 在控制器中使用
if (Gate::denies('edit-post', $post)) {
abort(403);
}
测试策略
编写单元测试验证RBAC功能:
class RBACTest extends PHPUnit_Framework_TestCase {
public function testPermissionCheck() {
$db = new PDO('sqlite::memory:');
// 初始化测试数据...
$rbac = new RBAC($db);
$this->assertTrue($rbac->userHasPermission(1, 'create_post'));
$this->assertFalse($rbac->userHasPermission(2, 'delete_post'));
}
}






