PHP项目代理与访问控制

wen PHP项目 1

本文目录导读:

PHP项目代理与访问控制

  1. 代理模式实现
  2. 访问控制系统
  3. 综合应用示例
  4. 最佳实践

我来为您详细介绍PHP项目中的代理与访问控制机制。

代理模式实现

简单代理类

<?php
// 代理接口
interface Subject {
    public function request($data);
}
// 真实主题类
class RealSubject implements Subject {
    public function request($data) {
        return "处理数据: " . $data;
    }
}
// 代理类
class Proxy implements Subject {
    private $realSubject;
    private $accessControl;
    public function __construct() {
        $this->realSubject = new RealSubject();
        $this->accessControl = new AccessControl();
    }
    public function request($data) {
        // 前置处理
        if (!$this->accessControl->checkPermission()) {
            throw new Exception("无权访问");
        }
        // 记录日志
        $this->logRequest($data);
        // 调用真实对象
        $result = $this->realSubject->request($data);
        // 后置处理
        $this->cacheResult($data, $result);
        return $result;
    }
    private function logRequest($data) {
        // 记录请求日志
    }
    private function cacheResult($key, $value) {
        // 缓存结果
    }
}
// 使用
$proxy = new Proxy();
try {
    echo $proxy->request("测试数据");
} catch (Exception $e) {
    echo "错误: " . $e->getMessage();
}

动态代理

<?php
class DynamicProxy {
    private $target;
    private $handlers = [];
    public function __construct($target) {
        $this->target = $target;
    }
    public function addHandler($method, callable $handler) {
        $this->handlers[$method] = $handler;
    }
    public function __call($name, $arguments) {
        // 检查是否需要前置处理
        if (isset($this->handlers['before'])) {
            call_user_func_array($this->handlers['before'], [$name, $arguments]);
        }
        // 调用目标方法
        $result = call_user_func_array([$this->target, $name], $arguments);
        // 检查是否需要后置处理
        if (isset($this->handlers['after'])) {
            $result = call_user_func_array($this->handlers['after'], [$name, $arguments, $result]);
        }
        return $result;
    }
}
// 使用
class UserService {
    public function getUser($id) {
        return "用户信息: " . $id;
    }
}
$userService = new UserService();
$proxy = new DynamicProxy($userService);
$proxy->addHandler('before', function($method, $args) {
    echo "前置处理: 调用 $method\n";
});
$proxy->addHandler('after', function($method, $args, $result) {
    echo "后置处理: $method 返回 $result\n";
    return $result;
});
echo $proxy->getUser(123);

访问控制系统

基于角色的访问控制(RBAC)

<?php
class RBAC {
    private $roles = [];
    private $permissions = [];
    private $userRoles = [];
    private $rolePermissions = [];
    // 添加角色
    public function addRole($roleName, $parentRole = null) {
        $this->roles[$roleName] = $parentRole;
    }
    // 添加权限
    public function addPermission($permissionName, $description = '') {
        $this->permissions[$permissionName] = $description;
    }
    // 分配角色给用户
    public function assignRole($userId, $roleName) {
        if (!isset($this->userRoles[$userId])) {
            $this->userRoles[$userId] = [];
        }
        $this->userRoles[$userId][] = $roleName;
    }
    // 授权角色权限
    public function grantPermission($roleName, $permissionName) {
        if (!isset($this->rolePermissions[$roleName])) {
            $this->rolePermissions[$roleName] = [];
        }
        $this->rolePermissions[$roleName][] = $permissionName;
    }
    // 检查用户是否有权限
    public function hasPermission($userId, $permissionName) {
        if (!isset($this->userRoles[$userId])) {
            return false;
        }
        $roles = $this->userRoles[$userId];
        foreach ($roles as $role) {
            if ($this->roleHasPermission($role, $permissionName)) {
                return true;
            }
        }
        return false;
    }
    private function roleHasPermission($roleName, $permissionName) {
        // 检查当前角色
        if (isset($this->rolePermissions[$roleName]) && 
            in_array($permissionName, $this->rolePermissions[$roleName])) {
            return true;
        }
        // 检查父角色
        if (isset($this->roles[$roleName]) && $this->roles[$roleName] !== null) {
            return $this->roleHasPermission($this->roles[$roleName], $permissionName);
        }
        return false;
    }
    // 获取用户所有权限
    public function getUserPermissions($userId) {
        $permissions = [];
        if (isset($this->userRoles[$userId])) {
            foreach ($this->userRoles[$userId] as $role) {
                $permissions = array_merge($permissions, $this->getRolePermissions($role));
            }
        }
        return array_unique($permissions);
    }
    private function getRolePermissions($roleName) {
        $permissions = [];
        if (isset($this->rolePermissions[$roleName])) {
            $permissions = $this->rolePermissions[$roleName];
        }
        if (isset($this->roles[$roleName]) && $this->roles[$roleName] !== null) {
            $permissions = array_merge($permissions, $this->getRolePermissions($this->roles[$roleName]));
        }
        return $permissions;
    }
}
// 使用示例
$rbac = new RBAC();
// 添加角色
$rbac->addRole('admin');
$rbac->addRole('editor', 'admin');
$rbac->addRole('viewer', 'editor');
// 添加权限
$rbac->addPermission('create_content', '创建内容');
$rbac->addPermission('edit_content', '编辑内容');
$rbac->addPermission('delete_content', '删除内容');
$rbac->addPermission('view_content', '查看内容');
// 分配权限
$rbac->grantPermission('admin', 'create_content');
$rbac->grantPermission('admin', 'edit_content');
$rbac->grantPermission('admin', 'delete_content');
$rbac->grantPermission('admin', 'view_content');
$rbac->grantPermission('editor', 'edit_content');
$rbac->grantPermission('editor', 'view_content');
$rbac->grantPermission('viewer', 'view_content');
// 分配角色给用户
$rbac->assignRole(1, 'admin');
$rbac->assignRole(2, 'editor');
$rbac->assignRole(3, 'viewer');
// 检查权限
echo "用户1是否有创建权限: " . ($rbac->hasPermission(1, 'create_content') ? '是' : '否') . "\n";
echo "用户2是否有删除权限: " . ($rbac->hasPermission(2, 'delete_content') ? '是' : '否') . "\n";

基于属性的访问控制(ABAC)

<?php
class ABAC {
    private $policies = [];
    private $userAttributes = [];
    private $resourceAttributes = [];
    private $environmentAttributes = [];
    // 添加访问策略
    public function addPolicy($policyName, $conditions, $effect = 'allow') {
        $this->policies[$policyName] = [
            'conditions' => $conditions,
            'effect' => $effect
        ];
    }
    // 设置用户属性
    public function setUserAttributes($userId, $attributes) {
        $this->userAttributes[$userId] = $attributes;
    }
    // 设置资源属性
    public function setResourceAttributes($resourceId, $attributes) {
        $this->resourceAttributes[$resourceId] = $attributes;
    }
    // 设置环境属性
    public function setEnvironmentAttributes($attributes) {
        $this->environmentAttributes = $attributes;
    }
    // 评估访问请求
    public function evaluateAccess($userId, $resourceId, $action) {
        foreach ($this->policies as $policy) {
            if ($this->evaluateConditions($policy['conditions'], $userId, $resourceId, $action)) {
                return $policy['effect'] === 'allow';
            }
        }
        return false; // 默认拒绝
    }
    private function evaluateConditions($conditions, $userId, $resourceId, $action) {
        foreach ($conditions as $condition) {
            if (!$this->evaluateCondition($condition, $userId, $resourceId, $action)) {
                return false;
            }
        }
        return true;
    }
    private function evaluateCondition($condition, $userId, $resourceId, $action) {
        $attributeValue = $this->getAttributeValue($condition['attribute'], $userId, $resourceId);
        switch ($condition['operator']) {
            case 'equals':
                return $attributeValue === $condition['value'];
            case 'greater_than':
                return $attributeValue > $condition['value'];
            case 'less_than':
                return $attributeValue < $condition['value'];
            case 'in':
                return in_array($attributeValue, $condition['value']);
            case 'contains':
                return strpos($attributeValue, $condition['value']) !== false;
            default:
                return false;
        }
    }
    private function getAttributeValue($attribute, $userId, $resourceId) {
        // 解析属性路径
        $parts = explode('.', $attribute);
        switch ($parts[0]) {
            case 'user':
                return $this->userAttributes[$userId][$parts[1]] ?? null;
            case 'resource':
                return $this->resourceAttributes[$resourceId][$parts[1]] ?? null;
            case 'environment':
                return $this->environmentAttributes[$parts[1]] ?? null;
            default:
                return null;
        }
    }
}
// 使用示例
$abac = new ABAC();
// 设置用户属性
$abac->setUserAttributes(1, [
    'role' => 'admin',
    'department' => 'IT',
    'clearance_level' => 5
]);
// 设置资源属性
$abac->setResourceAttributes('doc_123', [
    'classification' => 'confidential',
    'owner' => 1,
    'department' => 'IT'
]);
// 设置环境属性
$abac->setEnvironmentAttributes([
    'time' => date('H:i'),
    'ip_address' => '192.168.1.100'
]);
// 添加策略
$abac->addPolicy('admin_access', [
    ['attribute' => 'user.role', 'operator' => 'equals', 'value' => 'admin']
], 'allow');
$abac->addPolicy('department_access', [
    ['attribute' => 'user.department', 'operator' => 'equals', 'value' => 'resource.department'],
    ['attribute' => 'user.clearance_level', 'operator' => 'greater_than', 'value' => 3]
], 'allow');
// 评估访问
$canAccess = $abac->evaluateAccess(1, 'doc_123', 'read');
echo "用户1是否可以访问文档: " . ($canAccess ? '是' : '否');

中间件式访问控制

<?php
class AccessControlMiddleware {
    private $rules = [];
    private $userProvider;
    public function __construct(callable $userProvider) {
        $this->userProvider = $userProvider;
    }
    // 添加访问规则
    public function addRule($path, $requirements, $method = 'GET') {
        $this->rules[] = [
            'path' => $path,
            'method' => $method,
            'requirements' => $requirements
        ];
    }
    // 处理请求
    public function handle($request, callable $next) {
        $user = call_user_func($this->userProvider);
        foreach ($this->rules as $rule) {
            if ($this->matchRule($rule, $request)) {
                if (!$this->checkRequirements($rule['requirements'], $user, $request)) {
                    return $this->denyAccess('无权访问此资源');
                }
            }
        }
        return $next($request);
    }
    private function matchRule($rule, $request) {
        $pathMatch = preg_match('#^' . $rule['path'] . '$#', $request['path']);
        $methodMatch = strtoupper($rule['method']) === strtoupper($request['method']) || 
                      $rule['method'] === '*';
        return $pathMatch && $methodMatch;
    }
    private function checkRequirements($requirements, $user, $request) {
        foreach ($requirements as $requirement) {
            if (!$this->checkRequirement($requirement, $user, $request)) {
                return false;
            }
        }
        return true;
    }
    private function checkRequirement($requirement, $user, $request) {
        switch ($requirement['type']) {
            case 'role':
                return in_array($requirement['value'], $user['roles'] ?? []);
            case 'permission':
                return in_array($requirement['value'], $user['permissions'] ?? []);
            case 'owner':
                return $user['id'] === $request['resource_owner'];
            case 'ip_whitelist':
                return in_array($request['ip'], $requirement['value']);
            case 'time_restriction':
                $currentTime = time();
                return $currentTime >= strtotime($requirement['start']) && 
                       $currentTime <= strtotime($requirement['end']);
            default:
                return false;
        }
    }
    private function denyAccess($message) {
        http_response_code(403);
        echo json_encode(['error' => $message]);
        exit;
    }
}
// 使用示例
$middleware = new AccessControlMiddleware(function() {
    // 从会话或token获取用户信息
    return [
        'id' => 1,
        'username' => 'admin',
        'roles' => ['admin', 'editor'],
        'permissions' => ['create_post', 'edit_post', 'delete_post']
    ];
});
// 添加规则
$middleware->addRule('/api/admin/.*', [
    ['type' => 'role', 'value' => 'admin']
]);
$middleware->addRule('/api/posts/create', [
    ['type' => 'permission', 'value' => 'create_post']
]);
$middleware->addRule('/api/posts/(\d+)/delete', [
    ['type' => 'permission', 'value' => 'delete_post'],
    ['type' => 'owner', 'value' => true]
]);
// 处理请求
$request = [
    'path' => '/api/posts/123/delete',
    'method' => 'POST',
    'ip' => '192.168.1.100',
    'resource_owner' => 1
];
$middleware->handle($request, function($req) {
    echo "请求处理成功";
});

综合应用示例

完整的代理+访问控制系统

<?php
// 数据库操作代理
class DatabaseProxy {
    private $db;
    private $accessControl;
    private $queryLog = [];
    public function __construct(PDO $db, $accessControl) {
        $this->db = $db;
        $this->accessControl = $accessControl;
    }
    public function query($sql, $params = []) {
        // 检查权限
        if (!$this->accessControl->canQuery($sql)) {
            throw new Exception("无权执行此查询");
        }
        // 记录查询
        $this->logQuery($sql, $params);
        // 执行查询
        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        return $stmt;
    }
    public function insert($table, $data) {
        // 检查写入权限
        if (!$this->accessControl->canWrite($table)) {
            throw new Exception("无权写入此表");
        }
        // 数据过滤
        $filteredData = $this->accessControl->filterData($table, $data);
        // 执行插入
        $columns = implode(', ', array_keys($filteredData));
        $placeholders = ':' . implode(', :', array_keys($filteredData));
        $sql = "INSERT INTO $table ($columns) VALUES ($placeholders)";
        $stmt = $this->db->prepare($sql);
        $stmt->execute($filteredData);
        return $this->db->lastInsertId();
    }
    public function update($table, $data, $where) {
        // 检查更新权限
        if (!$this->accessControl->canUpdate($table)) {
            throw new Exception("无权更新此表");
        }
        // 数据过滤
        $filteredData = $this->accessControl->filterData($table, $data);
        // 构建SET子句
        $sets = [];
        foreach ($filteredData as $column => $value) {
            $sets[] = "$column = :$column";
        }
        $sql = "UPDATE $table SET " . implode(', ', $sets) . " WHERE $where";
        $stmt = $this->db->prepare($sql);
        $stmt->execute($filteredData);
        return $stmt->rowCount();
    }
    private function logQuery($sql, $params) {
        $this->queryLog[] = [
            'time' => date('Y-m-d H:i:s'),
            'sql' => $sql,
            'params' => $params
        ];
    }
    public function getQueryLog() {
        return $this->queryLog;
    }
}
// 文件操作代理
class FileProxy {
    private $accessControl;
    private $allowedExtensions = ['txt', 'pdf', 'doc', 'docx'];
    private $uploadDir = '/uploads/';
    public function __construct($accessControl) {
        $this->accessControl = $accessControl;
    }
    public function upload($file, $userId) {
        // 检查上传权限
        if (!$this->accessControl->canUpload($userId)) {
            throw new Exception("无权上传文件");
        }
        // 检查文件类型
        $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
        if (!in_array($extension, $this->allowedExtensions)) {
            throw new Exception("不支持的文件类型");
        }
        // 检查文件大小
        if ($file['size'] > 10 * 1024 * 1024) { // 10MB
            throw new Exception("文件过大");
        }
        // 生成安全的文件名
        $safeName = $this->generateSafeFileName($file['name']);
        $targetPath = $this->uploadDir . $userId . '/' . $safeName;
        // 创建目录
        if (!is_dir(dirname($targetPath))) {
            mkdir(dirname($targetPath), 0755, true);
        }
        // 移动文件
        if (move_uploaded_file($file['tmp_name'], $targetPath)) {
            return [
                'success' => true,
                'path' => $targetPath,
                'name' => $safeName
            ];
        }
        throw new Exception("文件上传失败");
    }
    public function download($fileId, $userId) {
        // 检查下载权限
        if (!$this->accessControl->canDownload($fileId, $userId)) {
            throw new Exception("无权下载此文件");
        }
        // 获取文件信息
        $fileInfo = $this->getFileInfo($fileId);
        // 检查文件是否存在
        if (!file_exists($fileInfo['path'])) {
            throw new Exception("文件不存在");
        }
        // 设置下载头
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . $fileInfo['name'] . '"');
        header('Content-Length: ' . filesize($fileInfo['path']));
        header('Cache-Control: no-cache');
        // 输出文件
        readfile($fileInfo['path']);
        exit;
    }
    private function generateSafeFileName($originalName) {
        $extension = pathinfo($originalName, PATHINFO_EXTENSION);
        $baseName = bin2hex(random_bytes(16));
        return $baseName . '.' . $extension;
    }
    private function getFileInfo($fileId) {
        // 从数据库获取文件信息
        return [
            'id' => $fileId,
            'name' => 'document.pdf',
            'path' => '/uploads/1/document.pdf'
        ];
    }
}
// 使用示例
try {
    // 初始化访问控制
    $accessControl = new RBAC();
    // ... 配置角色和权限
    // 数据库代理
    $pdo = new PDO('mysql:host=localhost;dbname=test', 'user', 'password');
    $dbProxy = new DatabaseProxy($pdo, $accessControl);
    // 文件代理
    $fileProxy = new FileProxy($accessControl);
    // 使用数据库代理
    $results = $dbProxy->query("SELECT * FROM users WHERE id = :id", ['id' => 1]);
    // 使用文件代理
    $fileProxy->upload($_FILES['document'], 1);
} catch (Exception $e) {
    echo "错误: " . $e->getMessage();
}

最佳实践

  1. 分层设计:将代理和访问控制逻辑与业务逻辑分离
  2. 缓存机制:缓存权限检查结果提高性能
  3. 日志记录:记录所有访问尝试和权限检查
  4. 异常处理:完善的错误处理和异常捕获
  5. 性能优化:使用索引、缓存等技术减少数据库查询
  6. 安全性:防止SQL注入、XSS攻击等安全威胁
  7. 可扩展性:设计灵活的角色和权限系统

这些实现提供了完整的PHP项目代理与访问控制解决方案,可以根据实际需求进行定制和扩展。

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