PHP 怎么写后台权限

wen PHP项目 2

本文目录导读:

PHP 怎么写后台权限

  1. 核心概念
  2. 基础架构流程图
  3. 完整的代码实现
  4. 注意事项
  5. 补充方案

在 PHP 中实现后台权限管理,通常涉及认证(你是谁)和授权(你能做什么)两个核心部分,下面是一个从简单到完善的实现方案,涵盖核心概念、代码示例和最佳实践。

核心概念

  1. 认证:验证用户身份(登录)
  2. 授权:验证用户是否有权限执行操作
  3. RBAC(基于角色的访问控制):将权限分配给角色,再将角色分配给用户

基础架构流程图

用户登录 → 验证身份 → 获取用户角色 → 获取角色权限 → 存储会话
                                                        ↓
用户请求操作 → 检查权限 → 有权限 → 执行操作
                        → 无权限 → 返回 403

完整的代码实现

数据结构设计

-- 用户表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    password VARCHAR(255) NOT NULL,  -- 存储hash值
    email VARCHAR(100),
    status TINYINT DEFAULT 1,        -- 1启用 0禁用
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 角色表
CREATE TABLE roles (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) UNIQUE NOT NULL,  -- 角色名称如:admin、editor
    description VARCHAR(255)
);
-- 权限表
CREATE TABLE permissions (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) UNIQUE NOT NULL,  -- 权限标识如:user.create
    description VARCHAR(255)
);
-- 用户-角色关联表
CREATE TABLE user_roles (
    user_id INT,
    role_id INT,
    PRIMARY KEY (user_id, role_id),
    FOREIGN KEY (user_id) REFERENCES users(id),
    FOREIGN KEY (role_id) REFERENCES roles(id)
);
-- 角色-权限关联表
CREATE TABLE role_permissions (
    role_id INT,
    permission_id INT,
    PRIMARY KEY (role_id, permission_id),
    FOREIGN KEY (role_id) REFERENCES roles(id),
    FOREIGN KEY (permission_id) REFERENCES permissions(id)
);

权限核心类实现

<?php
// Permission.php - 权限管理核心类
class PermissionManager {
    private $db;
    public function __construct($pdo) {
        $this->db = $pdo;
    }
    /**
     * 获取用户的权限列表
     * @param int $userId 用户ID
     * @return array 权限列表
     */
    public function getUserPermissions($userId) {
        $sql = "SELECT DISTINCT p.name 
                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($sql);
        $stmt->execute([$userId]);
        return $stmt->fetchAll(PDO::FETCH_COLUMN);
    }
    /**
     * 检查用户是否有某个权限
     * @param int $userId 用户ID
     * @param string $permission 权限标识
     * @return bool
     */
    public function hasPermission($userId, $permission) {
        $sql = "SELECT COUNT(*) 
                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 = ? AND p.name = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$userId, $permission]);
        return $stmt->fetchColumn() > 0;
    }
    /**
     * 检查用户是否有多个权限中的任意一个
     * @param int $userId 用户ID
     * @param array $permissions 权限标识数组
     * @return bool
     */
    public function hasAnyPermission($userId, array $permissions) {
        foreach ($permissions as $permission) {
            if ($this->hasPermission($userId, $permission)) {
                return true;
            }
        }
        return false;
    }
    /**
     * 获取用户角色列表
     * @param int $userId
     * @return array
     */
    public function getUserRoles($userId) {
        $sql = "SELECT r.name, r.description 
                FROM roles r
                INNER JOIN user_roles ur ON r.id = ur.role_id
                WHERE ur.user_id = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$userId]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}
?>

认证类实现

<?php
// Auth.php - 用户认证类
class Auth {
    private $db;
    private $permissionManager;
    public function __construct($pdo) {
        session_start();
        $this->db = $pdo;
        $this->permissionManager = new PermissionManager($pdo);
    }
    /**
     * 用户登录
     * @param string $username
     * @param string $password
     * @return bool
     */
    public function login($username, $password) {
        $sql = "SELECT * FROM users WHERE username = ? AND status = 1";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$username]);
        $user = $stmt->fetch();
        if ($user && password_verify($password, $user['password'])) {
            // 登录成功,创建会话
            $_SESSION['user_id'] = $user['id'];
            $_SESSION['username'] = $user['username'];
            $_SESSION['last_login'] = time();
            // 存储权限到session,避免每次查询数据库
            $_SESSION['permissions'] = $this->permissionManager->getUserPermissions($user['id']);
            $_SESSION['roles'] = $this->permissionManager->getUserRoles($user['id']);
            // 更新最后登录时间(可选)
            $this->updateLastLogin($user['id']);
            return true;
        }
        return false;
    }
    /**
     * 检查用户是否已登录
     * @return bool
     */
    public function isLoggedIn() {
        return isset($_SESSION['user_id']);
    }
    /**
     * 获取当前登录用户信息
     * @return array|null
     */
    public function getCurrentUser() {
        if (!$this->isLoggedIn()) {
            return null;
        }
        $sql = "SELECT * FROM users WHERE id = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$_SESSION['user_id']]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
    /**
     * 登出
     */
    public function logout() {
        $_SESSION = array();
        if (ini_get("session.use_cookies")) {
            $params = session_get_cookie_params();
            setcookie(session_name(), '', time() - 42000, 
                $params["path"], $params["domain"], $params["secure"], $params["httponly"]
            );
        }
        session_destroy();
    }
    /**
     * 权限检查中间件函数
     * @param string $permission 所需权限
     */
    public function requirePermission($permission) {
        if (!$this->isLoggedIn()) {
            header('Location: /login.php');
            exit;
        }
        if (!$this->hasPermission($permission)) {
            http_response_code(403);
            die('403 禁止访问:您没有权限执行此操作');
        }
    }
    /**
     * 角色检查中间件函数
     * @param array $roles 允许的角色
     */
    public function requireRole(array $roles) {
        if (!$this->isLoggedIn()) {
            header('Location: /login.php');
            exit;
        }
        $userRoles = $_SESSION['roles'] ?? [];
        foreach ($userRoles as $userRole) {
            if (in_array($userRole['name'], $roles)) {
                return;
            }
        }
        http_response_code(403);
        die('403 禁止访问:您没有权限执行此操作');
    }
    /**
     * 快速检查权限(从session读取)
     * @param string $permission
     * @return bool
     */
    public function hasPermission($permission) {
        if (!$this->isLoggedIn()) {
            return false;
        }
        $permissions = $_SESSION['permissions'] ?? [];
        return in_array($permission, $permissions);
    }
    private function updateLastLogin($userId) {
        $sql = "UPDATE users SET last_login = NOW() WHERE id = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$userId]);
    }
}
?>

中间件封装(适用于不同框架)

<?php
// middleware.php - 权限中间件示例
/**
 * 通用权限检查函数(适用于任何项目)
 */
function checkPermission($pdo, $userId, $permission) {
    $permManager = new PermissionManager($pdo);
    return $permManager->hasPermission($userId, $permission);
}
/**
 * 路由级别的权限检查(适用于MVC结构)
 */
class PermissionMiddleware {
    public static function handle($pdo, $permission) {
        session_start();
        if (!isset($_SESSION['user_id'])) {
            header('Location: /login.php');
            exit;
        }
        $permManager = new PermissionManager($pdo);
        if (!$permManager->hasPermission($_SESSION['user_id'], $permission)) {
            http_response_code(403);
            die('403 禁止访问');
        }
    }
}
?>

在业务代码中使用

<?php
// user_management.php - 业务实现示例
require_once 'config.php'; // 数据库配置
require_once 'Auth.php';
require_once 'Permission.php';
// 初始化
$auth = new Auth($pdo);
// 示例1:路由级权限控制
if ($_SERVER['REQUEST_URI'] === '/users') {
    $auth->requirePermission('user.view');
}
// 示例2:操作级权限控制
if ($_POST['action'] === 'create_user') {
    $auth->requirePermission('user.create');
    // 创建用户逻辑...
}
// 示例3:角色级控制
if ($_SERVER['REQUEST_URI'] === '/admin') {
    $auth->requireRole(['admin', 'super_admin']);
}
// 示例4:模板中使用条件判断权限
?>
<!-- in view.php -->
<?php if ($auth->hasPermission('user.edit')): ?>
    <button class="btn btn-edit">编辑</button>
<?php endif; ?>
<?php if ($auth->hasPermission('user.delete')): ?>
    <button class="btn btn-delete">删除</button>
<?php endif; ?>
<?php
// 示例5:动态路由权限(针对不同功能模块)
function checkRoutePermission($pdo, $route) {
    $permissionMap = [
        'product/view' => 'product.view',
        'product/create' => 'product.create',
        'product/edit' => 'product.edit',
        'product/delete' => 'product.delete',
    ];
    if (isset($permissionMap[$route])) {
        $auth = new Auth($pdo);
        $auth->requirePermission($permissionMap[$route]);
    }
}
?>

数据库初始化数据

-- 初始化数据
INSERT INTO roles (name, description) VALUES 
('admin', '超级管理员'),
('editor', '编辑'),
('viewer', '只读用户');
INSERT INTO users (username, password, email) VALUES 
('admin', '$2y$10$...hash...', 'admin@example.com');
-- 分配角色
INSERT INTO user_roles (user_id, role_id) VALUES 
(1, 1); -- admin用户分配 admin角色
-- 权限分配
INSERT INTO permissions (name, description) VALUES 
('user.view', '查看用户'),
('user.create', '创建用户'),
('user.edit', '编辑用户'),
('user.delete', '删除用户'),
('product.view', '查看产品'),
('product.create', '创建产品'),
('product.edit', '编辑产品'),
('product.delete', '删除产品');
-- 给角色分配权限
INSERT INTO role_permissions (role_id, permission_id) VALUES 
(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), -- admin 所有权限
(2, 1), (2, 5), (2, 6), (2, 7), -- editor:查看和编辑
(3, 1), (3, 5); -- viewer:只读

注意事项

安全要点

  • 密码存储:使用 password_hash()password_verify(),不要使用MD5
  • SQL注入:使用预处理语句(PDO)
  • CSRF防护:在表单操作中加入CSRF token
  • XSS防护:输出时使用 htmlspecialchars()

性能优化

// 缓存权限到session,避免每次查询数据库
// 可以在用户登录时加载一次
$_SESSION['permissions'] = $permManager->getUserPermissions($userId);
// 使用Redis等缓存系统存储权限数据
// 特别是对权限变更频繁的系统,使用失效时间策略

最佳实践

  • 权限粒度:根据业务复杂度决定,可以是「目录/操作」级别
  • 权限命名:推荐使用 模块.操作 格式,如 user.create
  • 日志记录:对敏感操作记录操作日志
  • 权限审计:定期审查用户权限,移除不必要权限
  • 测试:为权限系统编写单元测试和集成测试

补充方案

使用第三方库

  • Laravel:内置优雅的权限系统(Spree、Gate、Policies)
  • Symfony:Voter系统
  • 独立库:phpCAS、php-auth、rbac

前端配合

// 前端根据权限动态显示按钮(临时方案)
// 更好的做法是后端根据权限渲染
fetch('/api/user/permissions')
    .then(response => response.json())
    .then(permissions => {
        if (!permissions.includes('user.create')) {
            document.getElementById('btn-create-user').style.display = 'none';
        }
    });

一个完整的权限系统需要:

  1. 数据库设计(用户、角色、权限及其关联表)
  2. 认证逻辑(登录/登出/会话管理)
  3. 授权逻辑(权限检查/角色区分)
  4. 安全措施(防注入、防XSS、CSRF)
  5. 性能和可扩展性考虑

按照上述方案,你就能够实现一个基础但完整可扩展的后台权限系统。

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