PHP 数据权限实现方案

wen PHP项目 2

本文目录导读:

PHP 数据权限实现方案

  1. 基于角色的数据权限方案
  2. 基于规则的动态权限方案
  3. 基于AOP注解的方式
  4. 通用解决方案封装
  5. 最佳实践建议

我来介绍几种PHP数据权限的实现方案,从简单到复杂,你可以根据项目需求选择合适的方案。

基于角色的数据权限方案

基础RBAC模型

<?php
// 权限配置类
class PermissionConfig {
    // 用户角色
    const ROLE_ADMIN = 'admin';      // 管理员
    const ROLE_MANAGER = 'manager';  // 部门经理
    const ROLE_STAFF = 'staff';      // 普通员工
    // 数据权限级别
    const SCOPE_ALL = 'all';          // 全部数据
    const SCOPE_DEPARTMENT = 'dept'; // 本部门数据
    const SCOPE_SELF = 'self';       // 本人数据
    const SCOPE_CUSTOM = 'custom';   // 自定义范围
    // 角色对应的默认数据权限
    private static $roleScope = [
        self::ROLE_ADMIN => self::SCOPE_ALL,
        self::ROLE_MANAGER => self::SCOPE_DEPARTMENT,
        self::ROLE_STAFF => self::SCOPE_SELF,
    ];
    public static function getScopeForRole($role) {
        return self::$roleScope[$role] ?? self::SCOPE_SELF;
    }
}

数据权限过滤类

<?php
class DataPermission {
    private $user;
    private $db;
    public function __construct($user, $db) {
        $this->user = $user;
        $this->db = $db;
    }
    /**
     * 生成数据权限SQL条件
     * @param string $alias 表别名
     * @param string $userIdField 用户ID字段
     * @param string $deptIdField 部门ID字段
     */
    public function getPermissionSQL($alias = '', $userIdField = 'user_id', $deptIdField = 'dept_id') {
        $scope = PermissionConfig::getScopeForRole($this->user->role);
        $aliasPrefix = $alias ? $alias . '.' : '';
        switch ($scope) {
            case PermissionConfig::SCOPE_ALL:
                return '1=1';
            case PermissionConfig::SCOPE_DEPARTMENT:
                return "{$aliasPrefix}{$deptIdField} IN (
                    SELECT dept_id FROM user_depts 
                    WHERE user_id = {$this->user->id}
                    UNION
                    SELECT dept_id FROM depts 
                    WHERE parent_id IN (
                        SELECT dept_id FROM user_depts 
                        WHERE user_id = {$this->user->id}
                    )
                )";
            case PermissionConfig::SCOPE_SELF:
                return "{$aliasPrefix}{$userIdField} = {$this->user->id}";
            case PermissionConfig::SCOPE_CUSTOM:
                return $this->getCustomScopeSQL();
            default:
                return '1=0';
        }
    }
    /**
     * 应用数据权限过滤
     */
    public function applyPermission($sql) {
        $permissionSQL = $this->getPermissionSQL();
        // 检查是否已有WHERE条件
        if (stripos($sql, ' WHERE ') !== false) {
            $sql .= " AND {$permissionSQL}";
        } else {
            $sql .= " WHERE {$permissionSQL}";
        }
        return $sql;
    }
    private function getCustomScopeSQL() {
        // 从用户权限表获取自定义的数据范围
        $sql = "SELECT data_ids FROM user_data_scopes 
                WHERE user_id = {$this->user->id}";
        $result = $this->db->query($sql);
        $ids = $result->fetchColumn();
        return $ids ? "id IN ({$ids})" : '1=0';
    }
}

使用示例

<?php
// 在查询中使用数据权限
class UserController {
    public function getUsers() {
        $user = getCurrentUser();
        $db = getDB();
        $permission = new DataPermission($user, $db);
        $sql = "SELECT * FROM users u 
                WHERE u.status = 1";
        // 应用数据权限
        $sql = $permission->applyPermission($sql);
        $result = $db->query($sql);
        return $result->fetchAll();
    }
}

基于规则的动态权限方案

规则引擎

<?php
class RuleEngine {
    private $rules = [];
    private $context;
    public function setContext($context) {
        $this->context = $context;
    }
    public function addRule($rule) {
        $this->rules[] = $rule;
    }
    public function execute() {
        foreach ($this->rules as $rule) {
            if ($rule->evaluate($this->context)) {
                return $rule->apply($this->context);
            }
        }
        return false;
    }
}
// 规则接口
interface Rule {
    public function evaluate($context);
    public function apply($context);
}
// 部门范围规则
class DepartmentRule implements Rule {
    public function evaluate($context) {
        return $context['role'] === 'manager';
    }
    public function apply($context) {
        return "dept_id IN (SELECT dept_id FROM user_depts 
                WHERE user_id = {$context['user_id']})";
    }
}
// 自定义范围规则
class CustomScopeRule implements Rule {
    public function evaluate($context) {
        return $context['role'] === 'project_leader';
    }
    public function apply($context) {
        return "project_id IN (SELECT project_id FROM project_leaders 
                WHERE user_id = {$context['user_id']})";
    }
}

动态规则配置

<?php
// 数据库表结构
CREATE TABLE data_permission_rules (
    id INT PRIMARY KEY AUTO_INCREMENT,
    role VARCHAR(50),
    rule_type VARCHAR(50),
    rule_config TEXT,
    priority INT DEFAULT 0,
    status TINYINT(1) DEFAULT 1
);
// 规则加载器
class RuleLoader {
    public function loadRules($role) {
        $sql = "SELECT * FROM data_permission_rules 
                WHERE role = '{$role}' AND status = 1 
                ORDER BY priority DESC";
        // 返回规则数组
        return $this->db->fetchAll($sql);
    }
    public function buildRule($row) {
        switch ($row['rule_type']) {
            case 'department':
                return new DepartmentRule();
            case 'custom':
                $rule = new CustomScopeRule();
                $rule->setConfig(json_decode($row['rule_config'], true));
                return $rule;
            // 更多规则类型...
        }
    }
}

基于AOP注解的方式

<?php
/**
 * 数据权限注解
 * @Annotation
 */
class DataPermissionAnnotation {
    public $subject;       // 数据主体
    public $scope;         // 权限范围
    public $field;         // 字段
}
// 使用注解的控制器
class OrderController {
    /**
     * @DataPermissionAnnotation(subject="order", scope="dept", field="dept_id")
     */
    public function getOrders() {
        // 业务逻辑
        return $this->orderService->getList();
    }
}
// 注解处理器
class DataPermissionAspect {
    public function process($controller, $method) {
        $reflection = new ReflectionMethod($controller, $method);
        $docComment = $reflection->getDocComment();
        if (preg_match('/@DataPermissionAnnotation\((.*?)\)/', $docComment, $matches)) {
            $config = $this->parseAnnotation($matches[1]);
            return $this->buildPermissionSQL($config);
        }
        return '1=1';
    }
}

通用解决方案封装

权限管理器

<?php
class PermissionManager {
    private static $instance;
    private $db;
    private $user;
    private $handlers = [];
    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    public function setUser($user) {
        $this->user = $user;
        return $this;
    }
    public function registerHandler($subject, $handler) {
        $this->handlers[$subject] = $handler;
        return $this;
    }
    public function buildQuery($subject, $table, $params = []) {
        $handler = $this->handlers[$subject] ?? null;
        if ($handler) {
            return $handler->buildQuery($this->user, $table, $params);
        }
        // 默认处理
        return $this->defaultHandler($table, $params);
    }
    private function defaultHandler($table, $params) {
        // 默认实现
        $sql = "SELECT * FROM {$table} WHERE 1=1";
        if (isset($params['dept_id'])) {
            $sql .= $this->buildDeptCondition($params['dept_id']);
        }
        return $sql;
    }
}
// 使用示例
PermissionManager::getInstance()
    ->setUser($currentUser)
    ->registerHandler('order', new OrderPermissionHandler())
    ->registerHandler('product', new ProductPermissionHandler());
$sql = PermissionManager::getInstance()->buildQuery('order', 'orders', [
    'dept_id' => 100,
    'status' => 1
]);

缓存优化

<?php
class PermissionCache {
    private $cache;
    private $ttl = 3600;
    public function getPermissionSQL($userId, $subject) {
        $key = "permission:{$userId}:{$subject}";
        return $this->cache->remember($key, $this->ttl, function() use ($userId, $subject) {
            return $this->buildPermissionSQL($userId, $subject);
        });
    }
    public function clearPermission($userId) {
        $pattern = "permission:{$userId}:*";
        $this->cache->deleteByPattern($pattern);
    }
}

最佳实践建议

架构设计

<?php
// 分层设计
class PermissionLayer {
    // 1. 认证层
    public function authenticate($token) {
        // 验证用户身份
    }
    // 2. 授权层
    public function authorize($user, $action, $resource) {
        // 验证操作权限
        if (!$this->checkPermission($user, $action, $resource)) {
            throw new UnauthorizedException('无权限执行此操作');
        }
    }
    // 3. 数据过滤层
    public function filter($query, $user) {
        // 添加数据过滤条件
        return $this->applyDataPermission($query, $user);
    }
    // 4. 敏感字段脱敏层
    public function mask($data, $user) {
        // 对敏感字段进行脱敏
        return $this->maskSensitiveFields($data, $user);
    }
}

性能优化

<?php
class OptimizedPermissionService {
    public function getAllowedIds($user, $type) {
        $key = "allowed_ids:{$type}:{$user->id}";
        // 1. 先查缓存
        if ($ids = $this->getFromCache($key)) {
            return $ids;
        }
        // 2. 缓存未命中,查询数据库
        $ids = $this->queryAllowedIds($user, $type);
        // 3. 放入缓存
        $this->setCache($key, $ids);
        return $ids;
    }
    // 批量查询优化
    public function filterBatchData($datas, $user) {
        $allowedIds = $this->getAllowedIds($user, 'data');
        // 使用array_filter进行内存过滤
        return array_filter($datas, function($data) use ($allowedIds) {
            return in_array($data['id'], $allowedIds);
        });
    }
}

安全考虑

<?php
class SecurePermission {
    // SQL注入防护
    public static function sanitizeValue($value) {
        return intval($value); // 或使用预编译语句
    }
    // 越权防护
    public static function preventPrivilegeEscalation($user, $requestedAction) {
        // 检查是否为高权限操作
        if (in_array($requestedAction, ['delete', 'update_all', 'export'])) {
            // 二次验证
            return $this->doubleVerification($user);
        }
        return true;
    }
    // 日志审计
    public static function audit($userId, $action, $data, $result) {
        $log = [
            'user_id' => $userId,
            'action' => $action,
            'data' => json_encode($data),
            'result' => $result ? 'success' : 'denied',
            'ip' => $_SERVER['REMOTE_ADDR'],
            'time' => date('Y-m-d H:i:s')
        ];
        // 写入审计日志
        self::writeAuditLog($log);
    }
}

选择数据权限方案时需要综合考虑:

  • 项目规模:大型项目建议使用规则引擎,小型项目使用简单的RBAC即可
  • 灵活性需求:需要动态调整权限时使用规则配置方案
  • 性能要求:高并发场景需要考虑缓存和优化策略
  • 安全性:必须防护SQL注入和越权访问

建议从基础RBAC开始,根据业务需求逐步演进出更复杂的权限模型,同时保持良好的扩展性和可维护性。

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