本文目录导读:

我来详细介绍PHP动态权限的实现方案:
基于RBAC的权限模型
数据库表结构
-- 用户表
CREATE TABLE `users` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`username` VARCHAR(50) UNIQUE NOT NULL,
`password` VARCHAR(255) NOT NULL,
`status` TINYINT DEFAULT 1,
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 角色表
CREATE TABLE `roles` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`description` VARCHAR(255),
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 用户角色关联表
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`)
);
-- 权限表
CREATE TABLE `permissions` (
`id` INT PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(100) NOT NULL,
`slug` VARCHAR(100) UNIQUE NOT NULL,
`description` VARCHAR(255),
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 角色权限关联表
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`)
);
权限管理核心类
<?php
class PermissionManager {
private $db;
private $cache;
public function __construct($db) {
$this->db = $db;
$this->cache = [];
}
/**
* 获取用户所有权限
*/
public function getUserPermissions($userId) {
// 检查缓存
if (isset($this->cache[$userId])) {
return $this->cache[$userId];
}
$sql = "SELECT DISTINCT p.slug
FROM permissions p
INNER JOIN role_permissions rp ON p.id = rp.permission_id
INNER JOIN user_roles ur ON rp.role_id = ur.role_id
WHERE ur.user_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
$permissions = $stmt->fetchAll(PDO::FETCH_COLUMN);
// 缓存结果
$this->cache[$userId] = $permissions;
return $permissions;
}
/**
* 检查用户是否有某个权限
*/
public function hasPermission($userId, $permissionSlug) {
$permissions = $this->getUserPermissions($userId);
return in_array($permissionSlug, $permissions);
}
/**
* 添加角色
*/
public function createRole($name, $description = '') {
$sql = "INSERT INTO roles (name, description) VALUES (?, ?)";
$stmt = $this->db->prepare($sql);
return $stmt->execute([$name, $description]);
}
/**
* 添加权限
*/
public function createPermission($name, $slug, $description = '') {
$sql = "INSERT INTO permissions (name, slug, description) VALUES (?, ?, ?)";
$stmt = $this->db->prepare($sql);
return $stmt->execute([$name, $slug, $description]);
}
/**
* 为用户分配角色
*/
public function assignRole($userId, $roleId) {
$sql = "INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)";
$stmt = $this->db->prepare($sql);
$result = $stmt->execute([$userId, $roleId]);
// 清除缓存
unset($this->cache[$userId]);
return $result;
}
/**
* 为角色分配权限
*/
public function assignPermissionToRole($roleId, $permissionId) {
$sql = "INSERT INTO role_permissions (role_id, permission_id) VALUES (?, ?)";
$stmt = $this->db->prepare($sql);
return $stmt->execute([$roleId, $permissionId]);
}
}
权限中间件/拦截器
<?php
class AuthMiddleware {
private $permissionManager;
public function __construct($permissionManager) {
$this->permissionManager = $permissionManager;
}
/**
* 权限验证中间件
*/
public function requirePermission($permissionSlug) {
// 获取当前用户ID(从session或token获取)
$userId = $this->getCurrentUserId();
if (!$userId) {
header('HTTP/1.1 401 Unauthorized');
echo json_encode(['error' => '未登录']);
exit;
}
if (!$this->permissionManager->hasPermission($userId, $permissionSlug)) {
header('HTTP/1.1 403 Forbidden');
echo json_encode(['error' => '没有权限']);
exit;
}
return true;
}
/**
* 检查用户角色
*/
public function requireRole($roleName) {
$userId = $this->getCurrentUserId();
$sql = "SELECT r.name FROM roles r
INNER JOIN user_roles ur ON r.id = ur.role_id
WHERE ur.user_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
$roles = $stmt->fetchAll(PDO::FETCH_COLUMN);
if (!in_array($roleName, $roles)) {
header('HTTP/1.1 403 Forbidden');
echo json_encode(['error' => '需要特定角色']);
exit;
}
}
private function getCurrentUserId() {
// 从session或token获取用户ID
session_start();
return $_SESSION['user_id'] ?? null;
}
}
使用示例
<?php
// 初始化
$db = new PDO('mysql:host=localhost;dbname=test', 'root', '');
$permManager = new PermissionManager($db);
$auth = new AuthMiddleware($permManager);
// 1. 创建权限
$permManager->createPermission('创建文章', 'article.create', '允许用户创建新文章');
$permManager->createPermission('编辑文章', 'article.edit', '允许用户编辑文章');
$permManager->createPermission('删除文章', 'article.delete', '允许用户删除文章');
// 2. 创建角色
$permManager->createRole('管理员', '系统管理员');
$permManager->createRole('编辑者', '内容编辑者');
// 3. 为角色分配权限
$permManager->assignPermissionToRole(1, 1); // 管理员有创建权限
$permManager->assignPermissionToRole(1, 2); // 管理员有编辑权限
$permManager->assignPermissionToRole(1, 3); // 管理员有删除权限
$permManager->assignPermissionToRole(2, 1); // 编辑者有创建权限
$permManager->assignPermissionToRole(2, 2); // 编辑者有编辑权限
// 4. 为用户分配角色
$permManager->assignRole(1, 1); // 用户1是管理员
$permManager->assignRole(2, 2); // 用户2是编辑者
// 5. 在控制器中使用
class ArticleController {
public function create() {
global $auth;
$auth->requirePermission('article.create');
// 创建文章的逻辑
echo "文章创建成功";
}
public function edit($id) {
global $auth;
$auth->requirePermission('article.edit');
// 编辑文章的逻辑
echo "文章编辑成功";
}
public function delete($id) {
global $auth;
$auth->requirePermission('article.delete');
// 删除文章的逻辑
echo "文章删除成功";
}
}
高级特性
基于路由的权限控制
<?php
// 路由配置
$routes = [
'/admin' => ['permission' => 'admin.access', 'redirect' => '/login'],
'/admin/users' => ['permission' => 'user.manage'],
'/admin/articles/create' => ['permission' => 'article.create'],
'/admin/articles/edit/*' => ['permission' => 'article.edit'],
];
// 路由中间件
function routeMiddleware($uri) {
global $auth;
foreach ($routes as $pattern => $config) {
if (matchRoute($pattern, $uri)) {
$auth->requirePermission($config['permission']);
return true;
}
}
// 默认允许访问
return true;
}
function matchRoute($pattern, $uri) {
// 简单的路由匹配
$pattern = str_replace('*', '.*', $pattern);
return preg_match('#^' . $pattern . '$#', $uri);
}
权限缓存优化
<?php
class PermissionManagerWithRedis extends PermissionManager {
private $redis;
public function __construct($db, $redis) {
parent::__construct($db);
$this->redis = $redis;
}
public function getUserPermissions($userId) {
// 尝试从Redis缓存读取
$cacheKey = "user_permissions:{$userId}";
$cached = $this->redis->get($cacheKey);
if ($cached !== false) {
return json_decode($cached, true);
}
// 从数据库获取
$permissions = parent::getUserPermissions($userId);
// 存入Redis,设置过期时间
$this->redis->setex($cacheKey, 3600, json_encode($permissions));
return $permissions;
}
public function clearUserCache($userId) {
$cacheKey = "user_permissions:{$userId}";
$this->redis->del($cacheKey);
unset($this->cache[$userId]);
}
}
最佳实践
- 权限粒度设计:权限名使用模块.操作格式(如 article.create)
- 缓存策略:使用Redis/Memcached缓存用户权限列表
- 权限变更通知:权限变更时清除对应缓存
- 日志记录:记录权限验证日志用于审计
- 前端配合:前端根据权限动态显示/隐藏功能按钮
这个动态权限系统可以灵活地管理用户权限,支持角色和权限的动态分配和修改,适合各种规模的PHP应用。