PHP 怎么PHP 动态权限

wen PHP项目 2

本文目录导读:

PHP 怎么PHP 动态权限

  1. 基于RBAC的权限模型
  2. 权限管理核心类
  3. 权限中间件/拦截器
  4. 使用示例
  5. 高级特性
  6. 最佳实践

我来详细介绍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]);
    }
}

最佳实践

  1. 权限粒度设计:权限名使用模块.操作格式(如 article.create)
  2. 缓存策略:使用Redis/Memcached缓存用户权限列表
  3. 权限变更通知:权限变更时清除对应缓存
  4. 日志记录:记录权限验证日志用于审计
  5. 前端配合:前端根据权限动态显示/隐藏功能按钮

这个动态权限系统可以灵活地管理用户权限,支持角色和权限的动态分配和修改,适合各种规模的PHP应用。

抱歉,评论功能暂时关闭!