本文目录导读:

我来为您详细介绍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();
}
最佳实践
- 分层设计:将代理和访问控制逻辑与业务逻辑分离
- 缓存机制:缓存权限检查结果提高性能
- 日志记录:记录所有访问尝试和权限检查
- 异常处理:完善的错误处理和异常捕获
- 性能优化:使用索引、缓存等技术减少数据库查询
- 安全性:防止SQL注入、XSS攻击等安全威胁
- 可扩展性:设计灵活的角色和权限系统
这些实现提供了完整的PHP项目代理与访问控制解决方案,可以根据实际需求进行定制和扩展。