本文目录导读:

是的,我很清楚如何用PHP实现基于角色的访问控制(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,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 角色表
CREATE TABLE roles (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) UNIQUE NOT NULL,
description VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 权限表
CREATE TABLE permissions (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) UNIQUE NOT NULL,
slug VARCHAR(100) UNIQUE NOT NULL,
description VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 用户角色关联表
CREATE TABLE user_roles (
user_id INT NOT NULL,
role_id INT NOT NULL,
assigned_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (user_id, role_id),
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE
);
-- 角色权限关联表
CREATE TABLE role_permissions (
role_id INT NOT NULL,
permission_id INT NOT NULL,
PRIMARY KEY (role_id, permission_id),
FOREIGN KEY (role_id) REFERENCES roles(id) ON DELETE CASCADE,
FOREIGN KEY (permission_id) REFERENCES permissions(id) ON DELETE CASCADE
);
核心RBAC类实现
<?php
class RBAC {
private $db;
private $cache = [];
public function __construct($db) {
$this->db = $db;
}
/**
* 为用户分配角色
*/
public function assignRole($userId, $roleId) {
$stmt = $this->db->prepare("INSERT INTO user_roles (user_id, role_id) VALUES (?, ?)");
return $stmt->execute([$userId, $roleId]);
}
/**
* 移除用户角色
*/
public function removeRole($userId, $roleId) {
$stmt = $this->db->prepare("DELETE FROM user_roles WHERE user_id = ? AND role_id = ?");
return $stmt->execute([$userId, $roleId]);
}
/**
* 获取用户的所有角色
*/
public function getUserRoles($userId) {
$cacheKey = "user_roles_{$userId}";
if (isset($this->cache[$cacheKey])) {
return $this->cache[$cacheKey];
}
$stmt = $this->db->prepare("
SELECT r.* FROM roles r
JOIN user_roles ur ON r.id = ur.role_id
WHERE ur.user_id = ?
");
$stmt->execute([$userId]);
$roles = $stmt->fetchAll(PDO::FETCH_ASSOC);
$this->cache[$cacheKey] = $roles;
return $roles;
}
/**
* 获取用户的所有权限
*/
public function getUserPermissions($userId) {
$cacheKey = "user_permissions_{$userId}";
if (isset($this->cache[$cacheKey])) {
return $this->cache[$cacheKey];
}
$stmt = $this->db->prepare("
SELECT DISTINCT p.* FROM permissions p
JOIN role_permissions rp ON p.id = rp.permission_id
JOIN user_roles ur ON rp.role_id = ur.role_id
WHERE ur.user_id = ?
");
$stmt->execute([$userId]);
$permissions = $stmt->fetchAll(PDO::FETCH_ASSOC);
$this->cache[$cacheKey] = $permissions;
return $permissions;
}
/**
* 检查用户是否有特定权限
*/
public function hasPermission($userId, $permissionSlug) {
$permissions = $this->getUserPermissions($userId);
$slugs = array_column($permissions, 'slug');
return in_array($permissionSlug, $slugs);
}
/**
* 检查用户是否拥有某个角色
*/
public function hasRole($userId, $roleName) {
$roles = $this->getUserRoles($userId);
$names = array_column($roles, 'name');
return in_array($roleName, $names);
}
/**
* 检查用户是否拥有所有指定权限(AND逻辑)
*/
public function hasAllPermissions($userId, array $permissionSlugs) {
foreach ($permissionSlugs as $slug) {
if (!$this->hasPermission($userId, $slug)) {
return false;
}
}
return true;
}
/**
* 检查用户是否拥有任一指定权限(OR逻辑)
*/
public function hasAnyPermission($userId, array $permissionSlugs) {
foreach ($permissionSlugs as $slug) {
if ($this->hasPermission($userId, $slug)) {
return true;
}
}
return false;
}
}
中间件实现
<?php
class RBACMiddleware {
private $rbac;
private $session;
public function __construct($rbac, $session) {
$this->rbac = $rbac;
$this->session = $session;
}
/**
* 权限检查中间件
*/
public function requirePermission($permissionSlug, $redirectUrl = '/login') {
if (!$this->session->isLoggedIn()) {
header("Location: {$redirectUrl}");
exit;
}
$userId = $this->session->getUserId();
if (!$this->rbac->hasPermission($userId, $permissionSlug)) {
http_response_code(403);
echo "Access Denied: You don't have the required permission.";
exit;
}
}
/**
* 角色检查中间件
*/
public function requireRole($roleName, $redirectUrl = '/login') {
if (!$this->session->isLoggedIn()) {
header("Location: {$redirectUrl}");
exit;
}
$userId = $this->session->getUserId();
if (!$this->rbac->hasRole($userId, $roleName)) {
http_response_code(403);
echo "Access Denied: You don't have the required role.";
exit;
}
}
}
实际应用示例
<?php
// 初始化
$db = new PDO("mysql:host=localhost;dbname=your_database", "username", "password");
$rbac = new RBAC($db);
// 1. 创建角色和权限
// 添加权限
$stmt = $db->prepare("INSERT INTO permissions (name, slug, description) VALUES (?, ?, ?)");
$stmt->execute(['创建文章', 'article.create', '允许创建新文章']);
$stmt->execute(['编辑文章', 'article.edit', '允许编辑现有文章']);
$stmt->execute(['删除文章', 'article.delete', '允许删除文章']);
$stmt->execute(['管理用户', 'user.manage', '允许管理用户账户']);
// 添加角色
$stmt = $db->prepare("INSERT INTO roles (name, description) VALUES (?, ?)");
$stmt->execute(['admin', '系统管理员']);
$stmt->execute(['editor', '内容编辑']);
$stmt->execute(['user', '普通用户']);
// 2. 分配权限给角色
// 管理员拥有所有权限
$stmt = $db->prepare("INSERT INTO role_permissions (role_id, permission_id) VALUES (?, ?)");
// 假设admin角色ID=1,所有权限ID 1-4
foreach ([1,2,3,4] as $permId) {
$stmt->execute([1, $permId]);
}
// 编辑者拥有创建和编辑文章的权限
foreach ([1,2] as $permId) {
$stmt->execute([2, $permId]);
}
// 3. 用户登录和使用RBAC
session_start();
class SessionManager {
public function isLoggedIn() {
return isset($_SESSION['user_id']);
}
public function getUserId() {
return $_SESSION['user_id'] ?? null;
}
}
$session = new SessionManager();
$middleware = new RBACMiddleware($rbac, $session);
// 模拟用户登录
$_SESSION['user_id'] = 1; // admin用户
// 4. 路由保护示例
// 文章创建页面
if ($_SERVER['REQUEST_URI'] === '/article/create') {
$middleware->requirePermission('article.create', '/login');
// 继续处理文章创建逻辑
echo "创建文章页面";
}
// 文章管理页面
if ($_SERVER['REQUEST_URI'] === '/admin/users') {
$middleware->requireRole('admin', '/login');
// 继续处理用户管理逻辑
echo "用户管理页面";
}
// 5. 细粒度权限检查
$userId = $session->getUserId();
if ($rbac->hasPermission($userId, 'article.edit')) {
// 显示编辑按钮
}
// 检查是否同时拥有多个权限
if ($rbac->hasAllPermissions($userId, ['article.create', 'article.edit'])) {
// 显示完整功能
}
高级功能:缓存优化
<?php
class CachedRBAC extends RBAC {
private $cacheExpiry = 300; // 5分钟缓存
public function getUserPermissions($userId) {
$cacheKey = "user_permissions_{$userId}";
$cached = apcu_fetch($cacheKey);
if ($cached !== false) {
return $cached;
}
$permissions = parent::getUserPermissions($userId);
apcu_store($cacheKey, $permissions, $this->cacheExpiry);
return $permissions;
}
// 当权限发生变化时清除缓存
public function clearUserCache($userId) {
apcu_delete("user_roles_{$userId}");
apcu_delete("user_permissions_{$userId}");
}
}
最佳实践建议
- 性能优化:使用缓存(Redis/Memcached)存储用户权限
- 懒加载:只在需要时加载权限数据
- 权限分层:设计合理的权限层级结构
- 审计日志:记录所有权限变更操作
- 测试覆盖:为RBAC逻辑编写单元测试
- 扩展性:考虑使用策略模式处理复杂权限规则
这个RBAC实现提供了完整的用户、角色、权限管理功能,可以灵活应对各种权限控制需求,你可以根据实际项目需求进行调整和扩展。