本文目录导读:

在 PHP 中实现访问控制列表(ACL,Access Control List)有多种方式,从简单的硬编码到基于数据库的动态权限系统,以下是几种常见的实现方法:
基于角色的简单 ACL(推荐新手使用)
<?php
class SimpleACL {
private $roles = [
'guest' => ['view'],
'user' => ['view', 'create', 'edit'],
'admin' => ['view', 'create', 'edit', 'delete', 'manage']
];
private $userRole;
public function __construct($role = 'guest') {
$this->userRole = $role;
}
public function hasPermission($permission) {
return in_array($permission, $this->roles[$this->userRole]);
}
public function checkAccess($permission) {
if (!$this->hasPermission($permission)) {
throw new Exception("权限不足");
}
return true;
}
}
// 使用示例
$user = new SimpleACL('user');
if ($user->hasPermission('create')) {
echo "可以创建文章";
}
?>
数据库驱动的 ACL 系统
数据库表结构
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
role_id INT
);
-- 角色表
CREATE TABLE roles (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50)
);
-- 权限表
CREATE TABLE permissions (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100),
description TEXT
);
-- 角色-权限关联表
CREATE TABLE role_permissions (
role_id INT,
permission_id INT,
PRIMARY KEY (role_id, permission_id)
);
PHP 实现
<?php
class DBAcl {
private $db;
private $cache = [];
public function __construct($dbConnection) {
$this->db = $dbConnection;
}
public function getUserPermissions($userId) {
// 使用缓存避免重复查询
if (isset($this->cache[$userId])) {
return $this->cache[$userId];
}
$stmt = $this->db->prepare("
SELECT p.name
FROM permissions p
JOIN role_permissions rp ON p.id = rp.permission_id
JOIN users u ON u.role_id = rp.role_id
WHERE u.id = ?
");
$stmt->execute([$userId]);
$permissions = $stmt->fetchAll(PDO::FETCH_COLUMN);
$this->cache[$userId] = $permissions;
return $permissions;
}
public function checkPermission($userId, $permissionName) {
$permissions = $this->getUserPermissions($userId);
return in_array($permissionName, $permissions);
}
}
// 使用示例
$acl = new DBAcl($pdo);
if ($acl->checkPermission(1, 'article.create')) {
echo "用户有创建文章的权限";
}
?>
使用现有库:phpCAS(更专业)
安装
composer require casbin/casbin
使用示例
<?php
require 'vendor/autoload.php';
use Casbin\Enforcer;
// 创建权限模型
$enforcer = new Enforcer('path/to/model.conf', 'path/to/policy.csv');
// 检查权限
if ($enforcer->enforce('alice', 'data1', 'read')) {
echo "alice 可以读取 data1";
} else {
echo "权限不足";
}
// 添加权限
$enforcer->addPermissionForUser('alice', 'data1', 'write');
// 获取用户所有权限
$permissions = $enforcer->getPermissionsForUser('alice');
?>
完整的企业级 ACL 实现
<?php
class AccessControlList {
private $rules = [];
private $user;
public function __construct($user) {
$this->user = $user;
$this->loadRules();
}
private function loadRules() {
// 从配置文件或数据库加载规则
$this->rules = [
'articles' => [
'view' => ['*'], // 所有角色
'create' => ['admin', 'editor'],
'edit' => ['admin', 'editor'],
'delete' => ['admin']
],
'users' => [
'view' => ['admin'],
'manage' => ['admin']
]
];
}
public function isAllowed($resource, $action) {
if (!isset($this->rules[$resource][$action])) {
return false;
}
$allowedRoles = $this->rules[$resource][$action];
if (in_array('*', $allowedRoles)) {
return true;
}
return in_array($this->user->role, $allowedRoles);
}
public function requirePermission($resource, $action) {
if (!$this->isAllowed($resource, $action)) {
throw new PermissionDeniedException("权限不足");
}
return true;
}
}
// 中间件使用示例
class AuthMiddleware {
public function handle($request, $next) {
$acl = new AccessControlList($request->user);
// 检查当前路由的权限
$resource = $request->route['resource'];
$action = $request->route['action'];
try {
$acl->requirePermission($resource, $action);
return $next($request);
} catch (PermissionDeniedException $e) {
return response()->json(['error' => '权限不足'], 403);
}
}
}
?>
性能优化技巧
<?php
class OptimizedACL {
private static $instance;
private $permissionsCache = [];
private $cacheTimeout = 3600; // 1小时
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// 使用 Redis 缓存
public function checkPermissionWithRedis($userId, $permission) {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$cacheKey = "acl:user:{$userId}:{$permission}";
// 检查缓存
if ($redis->exists($cacheKey)) {
return (bool)$redis->get($cacheKey);
}
// 数据库查询
$result = $this->queryDatabase($userId, $permission);
// 设置缓存
$redis->setex($cacheKey, $this->cacheTimeout, $result ? 1 : 0);
return $result;
}
}
?>
选择建议
- 小型项目:使用基于角色的简单 ACL(方法1)
- 中型项目:使用数据库驱动的 ACL(方法2)
- 大型/企业级项目:使用专业库如 phpCAS(方法3)
- 需要高性能:添加 Redis 缓存(方法5)
推荐从简单方法开始,根据项目需求逐步升级,权限系统宁严勿松,后期放宽比收紧容易得多。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播