本文目录导读:

在PHP中实现多角色权限控制,有几种成熟的方案可供选择,我为你整理了一套从基础到进阶的完整实践方案:
最简方案:基于角色的硬编码
适合小型项目或原型开发,通过简单的角色判断来控制访问权限。
<?php
// 定义角色常量
const ROLE_ADMIN = 'admin'; // 超级管理员
const ROLE_MANAGER = 'manager'; // 运营经理
const ROLE_EDITOR = 'editor'; // 内容编辑
const ROLE_USER = 'user'; // 普通用户
// 简单的权限判断
if ($_SESSION['role'] === ROLE_ADMIN) {
// 管理员专属功能
echo "你可以管理所有用户";
} elseif ($_SESSION['role'] === ROLE_MANAGER) {
// 经理可以审核文章
echo "你可以审核文章";
} else {
// 普通用户只能看
echo "你只能浏览内容";
}
优点:简单直接,代码量少 缺点:不易扩展,角色多了会比较混乱
推荐方案:RBAC(基于角色的访问控制)
这是目前最主流、最推荐的方案,适合中小型项目,包括三个核心表:
数据库设计
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
email VARCHAR(100),
status TINYINT DEFAULT 1, -- 1启用 0禁用
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 角色表
CREATE TABLE roles (
id INT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(50) UNIQUE NOT NULL,
description VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 权限表
CREATE TABLE permissions (
id INT PRIMARY KEY AUTO_INCREMENT,
perm_key VARCHAR(50) UNIQUE NOT NULL, -- 权限标识,如 user:create
perm_name VARCHAR(100) NOT NULL, -- 权限名称,如 创建用户
module VARCHAR(50) -- 所属模块
);
-- 用户-角色关联表(多对多)
CREATE TABLE user_roles (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
role_id INT NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (role_id) REFERENCES roles(id),
UNIQUE KEY (user_id, role_id) -- 防止重复分配
);
-- 角色-权限关联表(多对多)
CREATE TABLE role_permissions (
id INT PRIMARY KEY AUTO_INCREMENT,
role_id INT NOT NULL,
permission_id INT NOT NULL,
FOREIGN KEY (role_id) REFERENCES roles(id),
FOREIGN KEY (permission_id) REFERENCES permissions(id),
UNIQUE KEY (role_id, permission_id)
);
代码实现
权限检查类
<?php
class Auth {
private $db;
private $user;
public function __construct($db) {
$this->db = $db;
$this->user = $this->getCurrentUser();
}
// 获取当前登录用户
private function getCurrentUser() {
if (isset($_SESSION['user_id'])) {
$userId = (int)$_SESSION['user_id'];
$query = "SELECT * FROM users WHERE id = ? AND status = 1";
$stmt = $this->db->prepare($query);
$stmt->execute([$userId]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
return null;
}
// 获取用户所有权限
public function getUserPermissions($userId = null) {
$userId = $userId ?: $this->user['id'];
$query = "SELECT DISTINCT p.perm_key
FROM permissions p
INNER JOIN role_permissions rp ON p.id = rp.permission_id
INNER JOIN user_roles ur ON rp.role_id = ur.role_id
WHERE ur.user_id = ?";
$stmt = $this->db->prepare($query);
$stmt->execute([$userId]);
return $stmt->fetchAll(PDO::FETCH_COLUMN);
}
// 检查用户是否有某权限
public function hasPermission($permKey) {
if (!$this->user) return false;
// 每次检查都查数据库,性能不佳,可以使用Session缓存
$permissions = $this->getUserPermissions();
return in_array($permKey, $permissions);
}
// 检查用户是否有某个角色
public function hasRole($roleName) {
if (!$this->user) return false;
$query = "SELECT r.role_name
FROM roles r
INNER JOIN user_roles ur ON r.id = ur.role_id
WHERE ur.user_id = ?";
$stmt = $this->db->prepare($query);
$stmt->execute([$this->user['id']]);
$roles = $stmt->fetchAll(PDO::FETCH_COLUMN);
return in_array($roleName, $roles);
}
// 在页面中使用
public function requirePermission($permKey) {
if (!$this->hasPermission($permKey)) {
header('HTTP/1.1 403 Forbidden');
echo json_encode(['error' => '没有权限执行此操作']);
exit;
}
}
}
中间件使用示例(Laravel风格)
<?php
// 在控制器方法中使用
class UserController {
private $auth;
public function __construct($auth) {
$this->auth = $auth;
}
public function create() {
// 检查权限:user:create
$this->auth->requirePermission('user:create');
// 业务逻辑
echo "创建用户成功";
}
public function delete($userId) {
// 删除用户通常需要管理员权限
$this->auth->requirePermission('user:delete');
// 业务逻辑
echo "删除用户成功";
}
public function export() {
// 或者使用角色判断
if (!$this->auth->hasRole('admin')) {
die('只有管理员可以导出数据');
}
// 业务逻辑
echo "导出数据成功";
}
}
权限分配管理界面(管理员使用)
<?php
// assign_permissions.php
class RoleManager {
private $db;
public function assignRoleToUser($userId, $roleId) {
// 先清理用户已有角色(可选)
$query = "DELETE FROM user_roles WHERE user_id = ?";
$this->db->prepare($query)->execute([$userId]);
// 分配新角色
$query = "INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)";
return $this->db->prepare($query)->execute([$userId, $roleId]);
}
public function syncRolePermissions($roleId, array $permissionIds) {
// 同步角色权限
$this->db->beginTransaction();
try {
// 删除旧的权限关联
$query = "DELETE FROM role_permissions WHERE role_id = ?";
$this->db->prepare($query)->execute([$roleId]);
// 添加新的权限
foreach ($permissionIds as $pid) {
$query = "INSERT INTO role_permissions (role_id, permission_id) VALUES (?, ?)";
$this->db->prepare($query)->execute([$roleId, $pid]);
}
$this->db->commit();
return true;
} catch (Exception $e) {
$this->db->rollBack();
return false;
}
}
}
进阶方案:ACL(访问控制列表)
在RBAC基础上更细粒度控制,支持按某个具体数据实例控制权限。
修改数据表结构
-- 增加资源表
CREATE TABLE resources (
id INT PRIMARY KEY AUTO_INCREMENT,
resource_type VARCHAR(50) NOT NULL, -- 如:post, article, comment
resource_id INT NOT NULL, -- 资源ID
owner_id INT NOT NULL, -- 资源拥有者
created_at TIMESTAMP
);
-- 用户-资源-操作 关联表
CREATE TABLE user_resource_permissions (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL,
resource_id INT NOT NULL,
permission_type VARCHAR(50), -- view, edit, delete
granted BOOLEAN DEFAULT 1 -- 是否允许
);
实现单个资源权限检查
<?php
class ACL extends Auth {
// 检查用户是否有权限操作某个资源
public function canOperate($userId, $resourceType, $resourceId, $operation) {
// 超级管理员直接放行
if ($this->hasRole('admin')) return true;
// 检查资源归属
$resourceQuery = "SELECT * FROM resources
WHERE resource_type = ? AND resource_id = ?";
$resource = $this->db->prepare($resourceQuery);
$resource->execute([$resourceType, $resourceId]);
$resourceData = $resource->fetch(PDO::FETCH_ASSOC);
if (!$resourceData) return false;
// 如果是自己的资源,允许操作(可配置规则)
if ($resourceData['owner_id'] === $userId) {
return true;
}
// 检查是否有特殊授权
$authQuery = "SELECT * FROM user_resource_permissions
WHERE user_id = ? AND resource_id = ? AND permission_type = ?";
$authStmt = $this->db->prepare($authQuery);
$authStmt->execute([$userId, $resourceData['id'], $operation]);
return $authStmt->fetch() !== false;
}
// 在控制器中使用
public function editArticle($articleId) {
if (!$this->canOperate($this->user['id'], 'article', $articleId, 'edit')) {
die('没有权限编辑这篇文章');
}
echo "文章编辑成功";
}
}
性能优化建议
当系统用户量比较大时,需要优化权限检查性能:
<?php
class OptimizedAuth extends Auth {
// 使用Redis缓存权限
private $redis;
public function __construct($db, $redis = null) {
parent::__construct($db);
$this->redis = $redis;
}
// 缓存用户的权限
private function cachePermissions($userId) {
$cacheKey = "user_permissions:{$userId}";
// 检查缓存
if ($this->redis->exists($cacheKey)) {
return json_decode($this->redis->get($cacheKey), true);
}
// 缓存未命中,查询数据库
$permissions = parent::getUserPermissions($userId);
// 存入缓存,有效期1小时
$this->redis->setex($cacheKey, 3600, json_encode($permissions));
return $permissions;
}
// 重置缓存(在权限变更时调用)
public function clearPermissionCache($userId) {
$cacheKey = "user_permissions:{$userId}";
$this->redis->del($cacheKey);
}
public function hasPermission($permKey, $userId = null) {
$userId = $userId ?: $this->user['id'];
$permissions = $this->cachePermissions($userId);
return in_array($permKey, $permissions);
}
}
总结建议
根据项目大小选择方案:
- 小型项目(个人博客,简单系统)→ 直接使用硬编码角色判断即可
- 中型项目(企业应用,内容管理系统)→ 推荐使用RBAC,完整实现多角色权限控制
- 大型复杂系统(多部门协作,数据隔离需求)→ 在RBAC基础上加入ACL支持
核心思路:
- 理清业务需求,确定有多少种角色,多少种权限操作
- 设计合理的数据结构
- 将权限检查逻辑封装成可复用的类
- 合理使用缓存技术提升性能
这样可以灵活应对多种场景,希望这些方案能帮到你。