これは、PHPでユーザーアカウント管理システムを作成する方法に関するシリーズのパート5です。他のパーツはここにあります:パート1、パート2、パート3、パート4。
前のセクションで、ロールだけでなく管理ユーザーアカウントの管理も終了しました。このパートでは、権限の作成と、ユーザーロールへの権限の割り当てと割り当て解除について説明します。
役割へのアクセス許可の割り当て
このシリーズの最初の部分で述べたように、役割は多対多の関係における権限に関連しています。ロールには多くの権限を設定でき、権限は多くのロールに属することができます。
すでにrolesテーブルを作成しました。次に、パーミッションを保持するためのパーミッションテーブルと、ロールとパーミッションテーブルの関係に関する情報を保持するためのpermission_roleという3番目のテーブルを作成します。
次のプロパティを持つ2つのテーブルを作成します。
権限テーブル:
CREATE TABLE `permissions` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` varchar(255) NOT NULL UNIQUE KEY,
`description` text NOT NULL
)
権限テーブル:
CREATE TABLE `permission_role` (
`id` int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
`role_id` int(11) NOT NULL,
`permission_id` int(11) NOT NULL,
KEY `role_id` (`role_id`),
KEY `permission_id` (`permission_id`),
CONSTRAINT `permission_role_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `permission_role_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`)
)
permit_roleテーブルでは、role_idはrolesテーブルのrole idを参照し、permission_idはpermissionsテーブルのpermissionid列を参照します。ロールにパーミッションを割り当てるには、permission_roleテーブルのrole_idに対してそのpermission_idのレコードを挿入するだけで、関係が確立されます。つまり、その役割からその権限の割り当てを解除する場合は、このpermission_roleテーブルのそのpermission_idに対するそのrole_idのレコードを削除するだけです。
上記のSQLクエリの最後の2行は、特定の役割または権限が削除されたときに、その権限のIDまたはその役割IDを持つpermission_roleテーブルのすべてのエントリもデータベースによって自動的に削除されることを保証する制約です。これを行うのは、permission_roleテーブルに、存在しないロールまたはパーミッションに関する関係情報を保持させたくないためです。
PHPMyAdminを使用して、これらの制約を手動で設定することもできます。permission_roleテーブルを選択し、[リレーショナルビュー]> [構造]タブに移動して値を入力するだけで、インターフェイスで設定できます。それでもできない場合は、下にコメントを残してください。サポートさせていただきます。
これで関係が設定されました。
ロールに権限を割り当てるページを作成しましょう。 roleList.phpページでは、さまざまな役割の横に「権限」ボタンが表示されています。このリンクをクリックすると、assignPermissions.phpというページに移動します。そのファイルをadmin/rolesフォルダー内に作成しましょう。
assignPermissions.php:
<?php include('../../config.php') ?>
<?php include(ROOT_PATH . '/admin/roles/roleLogic.php') ?>
<?php
$permissions = getAllPermissions();
if (isset($_GET['assign_permissions'])) {
$role_id = $_GET['assign_permissions']; // The ID of the role whose permissions we are changing
$role_permissions = getRoleAllPermissions($role_id); // Getting all permissions belonging to role
// array of permissions id belonging to the role
$r_permissions_id = array_column($role_permissions, "id");
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Admin Area - Assign permissions </title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" />
<!-- Custome styles -->
<link rel="stylesheet" href="../../static/css/style.css">
</head>
<body>
<?php include(INCLUDE_PATH . "/layouts/admin_navbar.php") ?>
<div class="col-md-4 col-md-offset-4">
<a href="roleList.php" class="btn btn-success">
<span class="glyphicon glyphicon-chevron-left"></span>
Roles
</a>
<hr>
<h1 class="text-center">Assign permissions</h1>
<br />
<?php if (count($permissions) > 0): ?>
<form action="assignPermissions.php" method="post">
<table class="table table-bordered">
<thead>
<tr>
<th>N</th>
<th>Role name</th>
<th class="text-center">Status</th>
</tr>
</thead>
<tbody>
<?php foreach ($permissions as $key => $value): ?>
<tr class="text-center">
<td><?php echo $key + 1; ?></td>
<td><?php echo $value['name']; ?></td>
<td>
<input type="hidden" name="role_id" value="<?php echo $role_id; ?>">
<!-- if current permission id is inside role's ids, then check it as already belonging to role -->
<?php if (in_array($value['id'], $r_permissions_id)): ?>
<input type="checkbox" name="permission[]" value="<?php echo $value['id'] ?>" checked>
<?php else: ?>
<input type="checkbox" name="permission[]" value="<?php echo $value['id'] ?>" >
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<tr>
<td colspan="3">
<button type="submit" name="save_permissions" class="btn btn-block btn-success">Save permissions</button>
</td>
</tr>
</tbody>
</table>
</form>
<?php else: ?>
<h2 class="text-center">No permissions in database</h2>
<?php endif; ?>
</div>
<?php include(INCLUDE_PATH . "/layouts/footer.php") ?>
</body>
</html>
ロールの「権限」ボタンをクリックすると、このページに移動します。しかし、今それをクリックしてこのassignPermissions.phpページにアクセスすると、getAllPermissions()関数が未定義であることを示すエラーメッセージが表示されます。このメソッドを追加する前に、PHPコードでこの権限の割り当てと割り当て解除を実際にどのように実装するかを見ていきましょう。
ロールの「permissions」ボタンをクリックすると、そのロールのIDが記載されたassignPermissions.phpページに移動します。ただし、権限の割り当てページを表示する前に、ロールIDを使用して、データベースからそのロールにすでに割り当てられているすべての権限を取得します。そして、パーミッションテーブルで利用可能なすべてのパーミッションも引き出します。これで、権限の2つの配列ができました。1つは役割に割り当てられたもので、もう1つはデータベースで使用可能なすべての権限です。前者の1つは、後者のサブセットです。
ロールにパーミッションを割り当てるということは、パーミッションのリスト全体からそのパーミッションをそのロールに属するパーミッションの配列に追加し、この情報全体をpermission_roleテーブルに保存することを意味します。ロールから権限の割り当てを解除するということは、そのロールに属する権限のリストからその特定の権限を削除することを意味します。
私たちのロジックは、データベースから利用可能なすべてのアクセス許可の配列をループすることです。次に、それらのIDごとに、そのIDがロールのアクセス許可のIDの配列にすでに含まれているかどうかを判断します。存在する場合は、ロールにすでにその権限があることを意味するため、チェックボックスの横に表示します。存在しない場合は、チェックされていないチェックボックスの横に表示されます。
すべてが表示された後、チェックされたチェックボックスをクリックすると権限の割り当てが解除され、チェックされていないチェックボックスをクリックするとロールに権限が割り当てられます。すべてのチェックとチェック解除が完了したら、ユーザーはテーブルの下にある[アクセス許可の保存]ボタンをクリックして、チェックされているすべてのアクセス許可をその役割に保存します。
これらすべての関数をroleLogic.phpファイルに追加しましょう。それらは:
roleLogic.php:
// ... other functions up here ...
function getAllPermissions(){
global $conn;
$sql = "SELECT * FROM permissions";
$permissions = getMultipleRecords($sql);
return $permissions;
}
function getRoleAllPermissions($role_id){
global $conn;
$sql = "SELECT permissions.* FROM permissions
JOIN permission_role
ON permissions.id = permission_role.permission_id
WHERE permission_role.role_id=?";
$permissions = getMultipleRecords($sql, 'i', [$role_id]);
return $permissions;
}
function saveRolePermissions($permission_ids, $role_id) {
global $conn;
$sql = "DELETE FROM permission_role WHERE role_id=?";
$result = modifyRecord($sql, 'i', [$role_id]);
if ($result) {
foreach ($permission_ids as $id) {
$sql_2 = "INSERT INTO permission_role SET role_id=?, permission_id=?";
modifyRecord($sql_2, 'ii', [$role_id, $id]);
}
}
$_SESSION['success_msg'] = "Permissions saved";
header("location: roleList.php");
exit(0);
}
権限を機能させる
この時点で、ユーザーの役割を特定できます。役割は権限に関連しているため、ユーザーの権限も知ることができます。
次に、これらの権限を機能させます。つまり、管理者ユーザーが権限を持っているアクションのみを実行できるようにします。ミドルウェア機能を使用してこれを実現します。ミドルウェアは基本的に、アクションが実行される前に実行されるコードまたは関数の一部です。通常、このミドルウェア関数は、アクションの動作を変更したり、チェックの結果に応じてアクションを完全に停止する可能性のあるいくつかのチェックを実行したりする場合があります。
たとえば、ユーザーには、作成-投稿、更新-投稿、および削除-投稿の権限がある場合があります。ログインして投稿を公開しようとすると、ミドルウェア機能はまず、このユーザーが公開投稿権限を持っているかどうかを確認します。この権限がある場合、ミドルウェア関数はtrueを返し、投稿が公開されます。投稿の公開権限がない場合、ミドルウェア機能は、投稿を公開する権限がないことを示すメッセージでリダイレクトします。
すべてのミドルウェア関数をmiddleware.phpという単一のファイル内に配置します。今すぐadminフォルダに作成し、次のコードを貼り付けます:
ミドルウェア.php:
<?php
// if user is NOT logged in, redirect them to login page
if (!isset($_SESSION['user'])) {
header("location: " . BASE_URL . "login.php");
}
// if user is logged in and this user is NOT an admin user, redirect them to landing page
if (isset($_SESSION['user']) && is_null($_SESSION['user']['role'])) {
header("location: " . BASE_URL);
}
// checks if logged in admin user can update post
function canUpdatePost($post_id = null){
global $conn;
if(in_array('update-post', $_SESSION['userPermissions'])){
if ($_SESSION['user']['role'] === "Author") { // author can update only posts that they themselves created
$sql = "SELECT user_id FROM posts WHERE id=?";
$post_result = getSingleRecord($sql, 'i', [$post_id]);
$post_user_id = $post_result['user_id'];
// if current user is the author of the post, then they can update the post
if ($post_user_id === $user_id) {
return true;
} else { // if post is not created by this author
return false;
}
} else { // if user is not author
return true;
}
} else {
return false;
}
}
// accepts user id and post id and checks if user can publis/unpublish a post
function canPublishPost() {
if(in_array(['permission_name' => 'publish-post'], $_SESSION['userPermissions'])){
// echo "<pre>"; print_r($_SESSION['userPermissions']); echo "</pre>"; die();
return true;
} else {
return false;
}
}
function canDeletePost() {
if(in_array('delete-post', $_SESSION['userPermissions'])){
return true;
} else {
return false;
}
}
function canCreateUser() {
if(in_array('create-user', $_SESSION['userPermissions'])){
return true;
} else {
return false;
}
}
function canUpdateUser() {
if(in_array('update-user', $_SESSION['userPermissions'])){
return true;
} else {
return false;
}
}
function canDeleteUser() {
if(in_array('delete-user', $_SESSION['userPermissions'])){
return true;
} else {
return false;
}
}
function canCreateRole($role_id) {
if(in_array('create-role', $_SESSION['userPermissions'])){
return true;
} else {
return false;
}
}
function canUpdateRole($role_id) {
if(in_array('update-role', $_SESSION['userPermissions'])){
return true;
} else {
return false;
}
}
function canDeleteRole($user_id, $post_id) {
if(in_array('delete-role', $_SESSION['userPermissions'])){
return true;
} else {
return false;
}
}
?>
"; die(); trueを返します。 } else{falseを返す; }} function canDeletePost(){if(in_array('delete-post'、$ _SESSION ['userPermissions'])){return true; } else{falseを返す; }} function canCreateUser(){if(in_array('create-user'、$ _SESSION ['userPermissions'])){return true; } else{falseを返す; }} function canUpdateUser(){if(in_array('update-user'、$ _SESSION ['userPermissions'])){return true; } else{falseを返す; }} function canDeleteUser(){if(in_array('delete-user'、$ _SESSION ['userPermissions'])){return true; } else{falseを返す; }} function canCreateRole($ role_id){if(in_array('create-role'、$ _SESSION ['userPermissions'])){return true; } else{falseを返す; }} function canUpdateRole($ role_id){if(in_array('update-role'、$ _SESSION ['userPermissions'])){return true; } else{falseを返す; }} function canDeleteRole($ user_id、$ post_id){if(in_array('delete-role'、$ _SESSION ['userPermissions'])){return true; } else{falseを返す; }}?> 最初のifステートメントは、ユーザーがログインしているかどうかを確認します。ユーザーがログインしていない場合は、ホームページにリダイレクトされます。 2番目のifステートメントは、ユーザーがログインしているかどうか、およびユーザーに役割があるかどうか(管理者)を確認します。ユーザーがログインしていて役割を持っていることがわかった場合、そのユーザーはページにアクセスします。そうでない場合は、ホームページにリダイレクトされます。
管理者以外のユーザーによるアクセスを制限するすべてのファイルで、このmiddleware.phpファイルをそのファイルに含める必要があります。したがって、通常のユーザーにアクセスさせたくないすべての管理ファイルには、このファイルを含めます。したがって、adminフォルダー内の2つのフォルダー、つまりユーザー、ロール内のすべてのファイルを開きます。各ファイルで、config.phpのインクルードのすぐ下に次の行を追加します。
そのように:
<?php include('../../config.php'); ?>
<?php require_once '../middleware.php'; ?>
これにより、管理者以外のユーザーがページにアクセスしようとするとリダイレクトされます。
また、このmiddleware.phpファイルでは、PHPのin_array()を使用して、テストしている権限がそのユーザーの権限の配列に含まれているかどうかを確認しています。 (管理者ユーザーがログインすると、すべてのアクセス許可が$ _SESSION ['userPermissions']というセッション変数配列に配置されます。)現在のアクセス許可がユーザーのアクセス許可の配列にある場合、そのユーザーがそのアクセス許可を持っていることを意味します。したがって、関数はtrueを返し、そうでない場合はfalseを返します。
ここで、ユーザーに権限があるかどうかを確認する場合、たとえば、公開投稿権限を実行するには、次のようにメソッドcanPublishPost()を呼び出す必要があります。
<?php if (canPublishPost()): ?>
<!-- User can publish post. Display publish post button -->
<?php else: ?>
<!-- User cannot publish post. Do not display publish post button -->
<?php endif ?>
また、ミドルウェアとして、投稿を更新する前に、まずcanUpdatePost()ミドルウェア関数を呼び出します。関数がユーザーに更新投稿権限がないことを確認して確認した場合、falseが返され、投稿の更新が許可されていないことを示すメッセージを表示して、ユーザーをホームページにリダイレクトできます。このように:
// checks if logged in admin user can update post
function updatePost($post_values){
global $conn;
if(canUpdatePost($post_values['id']){
// proceed to update post
} else {
// redirect back to homepage with message that says user is not permitted to update post
}
}
投稿の公開/非公開についても同じです:
function togglePublishPost($post_id)
{
if (!canPublishPost($_SESSION['user']['id'])) {
// redirect them back to dashboard with the message that they don't have the permission to publish post
}
// proceed to publish post
}
このチュートリアルの最後の部分は、ユーザープロファイルを更新し、登録ユーザーが自分のアカウントを削除できるようにすることです。
フォローしていただきありがとうございます。何か言いたいことがあれば、コメント欄に入れてください。