37、PHP用户权限管理与二进制操作实践

PHP用户权限管理与二进制操作实践

1. 权限常量与方法定义

在PHP开发中,为了管理用户权限,我们首先定义了一系列常量。这些常量与作者(Author)相关的权限有关,在 Author 实体类中进行定义:

<?php
namespace Ijdb\Entity;
class Author {
    const EDIT_JOKES = 1;
    const DELETE_JOKES = 2;
    const LIST_CATEGORIES = 3;
    const EDIT_CATEGORIES = 4;
    const REMOVE_CATEGORIES = 5;
    const EDIT_USER_ACCESS = 6;
    // …
    public function hasPermission($permission) {
        // …
    }
}

常量命名遵循惯例,使用大写字母,单词之间用下划线分隔。访问常量时,使用 :: 操作符,无需创建实例。

2. 权限检查方法与接口

为了实现页面级别的权限访问控制,我们添加了新的方法 checkPermission IjdbRoutes 类中:

public function checkPermission($permission): bool {
    $user = $this->authentication->getUser();
    if ($user && $user->hasPermission($permission)) {
        return true;
    } else {
        return false;
    }
}

同时,修改 Routes 接口,包含 checkPermission 方法:

<?php
namespace Ninja;
interface Routes
{
    public function getRoutes(): array;
    public function getAuthentication(): \Ninja\Authentication;
    public function checkPermission($permission): bool;
}
3. 路由权限设置

EntryPoint 类的 $routes 数组中,为每个页面指定所需的权限。例如,对于分类相关的页面:

'category/edit' => [
    'POST' => [
        'controller' => $categoryController,
        'action' => 'saveEdit'
    ],
    'GET' => [
        'controller' => $categoryController,
        'action' => 'edit'
    ],
    'login' => true,
    'permissions' => \Ijdb\Entity\Author::EDIT_CATEGORIES
],
'category/delete' => [
    'POST' => [
        'controller' => $categoryController,
        'action' => 'delete'
    ],
    'login' => true,
    'permissions' => \Ijdb\Entity\Author::REMOVE_CATEGORIES
],
'category/list' => [
    'GET' => [
        'controller' => $categoryController,
        'action' => 'list'
    ],
    'login' => true,
    'permissions' => \Ijdb\Entity\Author::LIST_CATEGORIES
],

EntryPoint 类中,会先进行登录检查,再进行权限检查:

if (isset($routes[$this->route]['login']) &&
    !$authentication->isLoggedIn()) {
    header('location: /login/error');
}
else if (isset($routes[$this->route]['permissions']) &&
    !$this->routes->checkPermission($routes[$this->route]['permissions'])) {
    header('location: /login/error');
}
else {
    // …
}
4. 创建权限分配表单

在实现 hasPermission 方法之前,需要创建页面来分配用户权限。添加以下路由:

'author/permissions' => [
    'GET' => [
        'controller' => $authorController,
        'action' => 'permissions'
    ],
    'POST' => [
        'controller' => $authorController,
        'action' => 'savePermissions'
    ],
    'login' => true
],
'author/list' => [
    'GET' => [
        'controller' => $authorController,
        'action' => 'list'
    ],
    'login' => true
],
4.1 作者列表页面

Register 控制器中添加 list 方法,用于获取所有注册用户列表并传递给模板:

public function list() {
    $authors = $this->authorsTable->findAll();
    return [
        'template' => 'authorlist.html.php',
        'title' => 'Author List',
        'variables' => [
            'authors' => $authors
        ]
    ];
}

模板 authorlist.html.php 如下:

<h2>User List</h2>
<table>
    <thead>
        <th>Name</th>
        <th>Email</th>
        <th>Edit</th>
    </thead>
    <tbody>
        <?php foreach ($authors as $author): ?>
            <tr>
                <td><?=$author->name;?></td>
                <td><?=$author->email;?></td>
                <td>
                    <a href="/author/permissions?id=<?=$author->id;?>">Edit Permissions</a>
                </td>
            </tr>
        <?php endforeach; ?>
    </tbody>
</table>
4.2 编辑作者权限页面

使用反射(Reflection)来动态生成权限复选框列表。在 Register 控制器中添加 permissions 方法:

public function permissions() {
    $author = $this->authorsTable->findById($_GET['id']);
    $reflected = new \ReflectionClass('\Ijdb\Entity\Author');
    $constants = $reflected->getConstants();
    return [
        'template' => 'permissions.html.php',
        'title' => 'Edit Permissions',
        'variables' => [
            'author' => $author,
            'permissions' => $constants
        ]
    ];
}

模板 permissions.html.php 如下:

<h2>Edit <?=$author->name?>’s Permissions</h2>
<form action="" method="post">
    <?php foreach ($permissions as $name => $value): ?>
        <div>
            <input name="permissions[]" type="checkbox" value="<?=$value?>"
                <?php if ($author->hasPermission($value)): echo 'checked'; endif; ?> />
            <label><?=$name?></label>
        </div>
    <?php endforeach; ?>
    <input type="submit" value="Submit" />
</form>
5. 权限存储方式

有两种方式来存储用户权限:

5.1 多表关联方式

创建 user_permission 表,包含 authorId permission 两列,为每个权限写入一条记录。例如,用户ID为4,具有 EDIT_JOKES LIST_CATEGORIES REMOVE_CATEGORIES 权限,表记录如下:
| authorId | permission |
| ---- | ---- |
| 4 | 1 |
| 4 | 3 |
| 4 | 5 |

hasPermission 方法示例:

public function hasPermission($permission) {
    $permissions = $this->userPermissionsTable->find('authorId', $this->id);
    foreach ($permissions as $perm) {
        if ($perm->permission == $permission) {
            return true;
        }
    }
    return false;
}
5.2 单字段二进制方式

author 表中为每个权限添加一个 TINYINT(1) 列:

CREATE TABLE `author` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `name` VARCHAR(255) DEFAULT NULL,
    `email` VARCHAR(255) DEFAULT NULL,
    `password` VARCHAR(255) DEFAULT NULL,
    `editJoke` TINYINT(1) NOT NULL DEFAULT 0,
    `deleteJokes` TINYINT(1) NOT NULL DEFAULT 0,
    `addCatgories` TINYINT(1) NOT NULL DEFAULT 0,
    `removeCategories` TINYINT(1) NOT NULL DEFAULT 0,
    `editUserAccess` TINYINT(1) NOT NULL DEFAULT 0,
    PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARSET=utf8;

使用 UPDATE 语句设置用户权限:

UPDATE `author` SET `editJokes` = 1, `listCategories` = 1, `removeCategories` = 1 WHERE `id` = 4;

检查用户权限时,直接检查对应列的值:

if ($author->editJokes == 1) {
    // 该作者可以编辑笑话
}
6. 二进制基础

计算机中所有数字都以二进制形式存储。例如,十进制数字6在二进制中表示为 0110 。二进制中,每个位(bit)代表不同的值,从右到左,每个位的值是前一位的2倍。将二进制 0110 转换为十进制的计算方法为:

0 x 8 +
1 x 4 +
1 x 2 +
0 x 1 = 6
7. 位运算与权限检查

使用单个二进制数存储用户权限,将每个权限分配到一个位上:
| 权限 | 二进制位值 |
| ---- | ---- |
| EDIT_USER_ACCESS | 32 |
| REMOVE_CATEGORIES | 16 |
| EDIT_CATEGORIES | 8 |
| LIST_CATEGORIES | 4 |
| DELETE_JOKES | 2 |
| EDIT_JOKES | 1 |

使用位运算( & )来检查用户是否具有某个权限。例如,检查用户是否具有 EDIT_CATEGORIES 权限:

if ($author->permissions & 8) {
    // 用户具有 EDIT_CATEGORIES 权限
}

为了提高代码可读性,将位值定义为常量:

const EDIT_JOKES = 1;
const DELETE_JOKES = 2;
const LIST_CATEGORIES = 4;
const EDIT_CATEGORIES = 8;
const REMOVE_CATEGORIES = 16;
const EDIT_USER_ACCESS = 32;

if ($author->permissions & EDIT_CATEGORIES) {
    // 用户具有 EDIT_CATEGORIES 权限
}

通过以上步骤,我们实现了一个完整的用户权限管理系统,包括权限定义、检查、分配和存储,同时利用二进制和位运算提高了权限检查的效率和代码的可维护性。

PHP用户权限管理与二进制操作实践

8. 位运算在PHP中的应用场景

位运算在PHP中除了用于权限管理,还有其他常见的应用场景。例如,在设置错误报告级别时,我们可以使用位运算来组合不同的错误类型。以下是一个简单的示例:

// 设置错误报告级别为警告和通知
error_reporting(E_WARNING | E_NOTICE);

// 检查是否设置了通知级别的错误报告
if (E_NOTICE & error_reporting()) {
    // 处理通知级别的错误
}

这个例子展示了如何使用位运算来设置和检查错误报告级别。当我们使用 | 运算符组合不同的错误类型时,实际上是在设置对应的二进制位。而使用 & 运算符来检查某个错误类型是否被设置,就是在检查对应的二进制位是否为1。

9. 权限管理系统的优化建议

为了提高权限管理系统的性能和可维护性,我们可以考虑以下优化建议:

9.1 缓存权限信息

频繁的数据库查询会影响系统性能。我们可以使用缓存机制(如Redis)来缓存用户的权限信息。当用户登录时,将其权限信息存储在缓存中,后续的权限检查直接从缓存中获取,减少数据库查询次数。以下是一个简单的示例:

// 获取用户权限信息
function getUserPermissions($userId) {
    $cache = new Redis();
    $cache->connect('127.0.0.1', 6379);

    $permissions = $cache->get("user_permissions_{$userId}");
    if (!$permissions) {
        // 从数据库中获取权限信息
        $permissions = $this->userPermissionsTable->find('authorId', $userId);
        // 将权限信息存储到缓存中
        $cache->set("user_permissions_{$userId}", serialize($permissions));
    } else {
        $permissions = unserialize($permissions);
    }

    return $permissions;
}
9.2 权限分组

当系统中的权限数量较多时,管理起来会变得复杂。我们可以将相关的权限分组,例如将与文章管理相关的权限分为一组,与用户管理相关的权限分为另一组。这样可以提高权限管理的效率,同时也方便用户理解和操作。以下是一个简单的权限分组示例:

const ARTICLE_MANAGEMENT = [
    EDIT_JOKES,
    DELETE_JOKES
];

const USER_MANAGEMENT = [
    EDIT_USER_ACCESS
];

// 检查用户是否具有文章管理权限
function hasArticleManagementPermissions($author) {
    foreach (ARTICLE_MANAGEMENT as $permission) {
        if ($author->hasPermission($permission)) {
            return true;
        }
    }
    return false;
}
10. 权限管理系统的流程图

下面是一个权限管理系统的流程图,展示了用户访问页面时的权限检查流程:

graph TD;
    A[用户访问页面] --> B{是否需要登录};
    B -- 是 --> C{用户是否已登录};
    C -- 是 --> D{是否需要权限检查};
    D -- 是 --> E{用户是否具有相应权限};
    E -- 是 --> F[显示页面];
    E -- 否 --> G[显示错误页面];
    C -- 否 --> G[显示错误页面];
    B -- 否 --> F[显示页面];
11. 总结

通过本文的介绍,我们详细了解了如何在PHP中实现用户权限管理系统。从权限常量的定义、权限检查方法的实现,到权限存储方式的选择,以及二进制和位运算在权限管理中的应用,我们逐步构建了一个完整的权限管理系统。

在实际开发中,我们可以根据系统的需求和规模选择合适的权限存储方式。多表关联方式适用于权限管理较为复杂的系统,而单字段二进制方式则更适合权限数量较少且对性能要求较高的系统。同时,我们还可以通过缓存权限信息和权限分组等优化措施,提高系统的性能和可维护性。

希望本文对你理解和实现PHP用户权限管理系统有所帮助,让你能够更好地保护系统的安全性和数据的完整性。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值