本文目录导读:

我来介绍几种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开始,根据业务需求逐步演进出更复杂的权限模型,同时保持良好的扩展性和可维护性。