Đây là phần 5 của loạt bài về cách tạo hệ thống quản lý tài khoản người dùng bằng PHP. Bạn có thể tìm các phần khác tại đây:part1, part2, part 3 và part 4.
Chúng tôi đã hoàn thành việc quản lý tài khoản người dùng quản trị trong phần cuối cùng cũng như các vai trò. Trong phần này, chúng ta sẽ tiến hành tạo quyền và gán cũng như bỏ gán quyền cho các vai trò của người dùng.
Chỉ định quyền cho các vai trò
Như tôi đã nói trong phần đầu tiên của loạt bài này, các vai trò có liên quan đến quyền trong mối quan hệ Nhiều-Nhiều. Một vai trò có thể có nhiều quyền và một quyền có thể thuộc về nhiều vai trò.
Chúng tôi đã tạo bảng vai trò. Bây giờ chúng ta sẽ tạo một bảng quyền để giữ các quyền và một bảng thứ ba có tên là allow_role để chứa thông tin về mối quan hệ giữa các vai trò và bảng quyền.
Tạo hai bảng để có các thuộc tính sau:
bảng quyền:
CREATE TABLE `permissions` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` varchar(255) NOT NULL UNIQUE KEY,
`description` text NOT NULL
)
bảng allow_role:
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`)
)
Trên bảng allow_role, role_id tham chiếu id vai trò trên bảng vai trò trong khi allow_id tham chiếu cột id quyền trên bảng quyền. Để gán quyền cho một vai trò, chúng tôi thực hiện điều đó bằng cách chỉ cần chèn một bản ghi của allow_id đó vào role_id trên bảng allow_role và mối quan hệ được thiết lập. Điều này có nghĩa là nếu chúng tôi muốn hủy gán quyền đó khỏi vai trò đó, chúng tôi chỉ cần xóa bản ghi của role_id đó so với allow_id đó trên bảng allow_role này.
Hai dòng cuối cùng của truy vấn SQL ở trên là các ràng buộc đảm bảo rằng khi một vai trò hoặc quyền cụ thể bị xóa, tất cả các mục nhập trong bảng allow_role có id của quyền đó hoặc id vai trò đó cũng sẽ bị cơ sở dữ liệu xóa tự động. Chúng tôi làm điều này vì chúng tôi không muốn bảng allow_role lưu giữ thông tin mối quan hệ về vai trò hoặc quyền không còn tồn tại.
Bạn cũng có thể thiết lập các ràng buộc này theo cách thủ công bằng cách sử dụng PHPMyAdmin:bạn có thể thực hiện trên giao diện đơn giản bằng cách chọn bảng allow_role và chuyển đến tab Relational view> Structure và chỉ cần điền các giá trị. Nếu bạn vẫn không thể thực hiện việc này, hãy để lại bình luận bên dưới và tôi sẽ cố gắng giúp bạn.
Bây giờ mối quan hệ đã được thiết lập.
Hãy tạo một trang để gán quyền cho một vai trò. Trên trang roleList.php của chúng tôi, chúng tôi liệt kê các vai trò khác nhau với nút 'quyền' bên cạnh mỗi vai trò. Nhấp vào liên kết này sẽ đưa chúng ta đến một trang có tên là allowPermissions.php. Bây giờ hãy tạo tệp đó bên trong thư mục admin / role.
gánPermissions.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>
Nhấp vào nút 'quyền' của một vai trò sẽ dẫn bạn đến trang này. Nhưng ngay bây giờ nếu bạn nhấp vào nó và truy cập vào trangignPermissions.php này, sẽ có một thông báo lỗi cho biết các hàm getAllPermissions () chưa được xác định. Trước khi thêm phương thức này, hãy xem lại cách chúng tôi thực sự triển khai việc gán và hủy gán quyền này trong mã PHP của chúng tôi.
Khi bạn nhấp vào nút 'quyền' của một vai trò, bạn sẽ được đưa đến trang gánPermissions.php với id của vai trò đó. Nhưng trước khi hiển thị trang quyền gán, chúng tôi sử dụng id vai trò để tìm nạp tất cả các quyền đã được gán cho vai trò đó từ cơ sở dữ liệu. Và sau đó, chúng tôi cũng đưa ra tất cả các quyền có sẵn trong bảng quyền. Bây giờ chúng ta có hai mảng quyền:mảng đã được gán cho một vai trò và tất cả các quyền có sẵn trong cơ sở dữ liệu của chúng ta. Một cái trước là một tập hợp con của cái sau.
Gán quyền cho một vai trò có nghĩa là thêm quyền đó từ danh sách tổng thể các quyền vào mảng quyền thuộc về vai trò đó và lưu toàn bộ thông tin này trong bảng allow_role. Bỏ chỉ định quyền khỏi một vai trò có nghĩa là xóa quyền cụ thể đó khỏi danh sách các quyền thuộc về vai trò đó.
Logic của chúng tôi là lặp qua một mảng tất cả các quyền có sẵn từ cơ sở dữ liệu, sau đó đối với mỗi id của chúng, chúng tôi xác định xem id đó đã có trong mảng id cho quyền của vai trò chưa. nếu nó tồn tại, điều đó có nghĩa là vai trò đã có quyền đó, vì vậy chúng tôi hiển thị nó cùng với một hộp kiểm đã chọn. Nếu nó không tồn tại, chúng tôi sẽ hiển thị nó cùng với một hộp kiểm không được chọn.
Sau khi mọi thứ đã được hiển thị, nhấp vào hộp kiểm đã chọn có nghĩa là bỏ gán quyền trong khi nhấp vào hộp kiểm chưa chọn có nghĩa là gán quyền cho vai trò. Sau khi hoàn tất việc kiểm tra và bỏ chọn, người dùng sau đó nhấp vào nút 'Lưu quyền' dưới bảng để lưu tất cả các quyền đã được kiểm tra cho vai trò đó.
Hãy thêm tất cả các hàm này vào tệp roleLogic.php. Đó là:
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);
}
Đưa quyền hoạt động
Tại thời điểm này, chúng tôi có thể xác định vai trò của người dùng là gì và vì vai trò có liên quan đến quyền, do đó chúng tôi cũng có thể biết quyền của họ.
Bây giờ chúng tôi muốn đặt các quyền này hoạt động:nghĩa là, để đảm bảo rằng người dùng quản trị chỉ được phép thực hiện những hành động mà anh ta có quyền. Chúng tôi sẽ đạt được điều này bằng cách sử dụng các chức năng phần mềm trung gian. Phần mềm trung gian về cơ bản là một đoạn mã hoặc một chức năng được thực thi trước khi một hành động được thực hiện. Thông thường, chức năng phần mềm trung gian này có thể sửa đổi hoạt động của hành động hoặc thực hiện một số kiểm tra có thể kết thúc hành động dừng hoàn toàn tùy thuộc vào kết quả của kiểm tra.
Ví dụ:người dùng có thể có các quyền tạo bài đăng, bài đăng cập nhật và xóa bài đăng. Nếu họ đã đăng nhập và cố gắng xuất bản một bài đăng, trước tiên, chức năng phần mềm trung gian của chúng tôi sẽ kiểm tra xem người dùng này có quyền xuất bản bài đăng hay không. Nếu họ có quyền này, chức năng phần mềm trung gian của chúng tôi sẽ trả về true và bài đăng sẽ được xuất bản. Nếu họ không có quyền xuất bản bài đăng, chức năng phần mềm trung gian của chúng tôi sẽ chuyển hướng họ trở lại với một thông báo nói rằng họ không có quyền xuất bản bài đăng.
Chúng tôi sẽ đặt tất cả các chức năng phần mềm trung gian của chúng tôi bên trong một tệp duy nhất có tên là middleware.php. Tạo nó ngay bây giờ trong quản trị thư mục và dán mã này vào nó:
middleware.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;
}
}
?>
"; chết(); trả về 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; }}?> Câu lệnh if đầu tiên kiểm tra xem người dùng đã đăng nhập chưa. Nếu người dùng chưa đăng nhập, họ sẽ được chuyển hướng đến trang chủ. Câu lệnh if thứ hai kiểm tra xem người dùng đã đăng nhập hay chưa và người đó có vai trò hay không (là quản trị viên). Nếu người dùng được phát hiện là đã đăng nhập và có vai trò, họ sẽ truy cập trang, nếu không, người dùng sẽ được chuyển hướng trở lại trang chủ.
Trong mọi tệp mà bạn muốn hạn chế người dùng không phải quản trị viên truy cập, bạn chỉ nên đưa tệp middleware.php này vào tệp đó. Vì vậy, tất cả các tệp quản trị của chúng tôi mà chúng tôi không muốn người dùng bình thường truy cập, chúng tôi sẽ bao gồm tệp này trong đó. Vì vậy, hãy mở tất cả các tệp trong hai thư mục bên trong thư mục quản trị, cụ thể là:người dùng, vai trò. Trong mỗi tệp, thêm dòng sau ngay bên dưới bao gồm cho config.php.
Như vậy:
<?php include('../../config.php'); ?>
<?php require_once '../middleware.php'; ?>
Và điều đó sẽ chuyển hướng bất kỳ người dùng không phải quản trị viên nào cố gắng truy cập trang.
Cũng trong tệp middleware.php này, chúng tôi đang sử dụng in_array () của PHP để kiểm tra xem quyền mà chúng tôi đang kiểm tra có nằm trong mảng quyền của người dùng đó hay không. (Khi người dùng quản trị đăng nhập, chúng tôi đặt tất cả quyền của họ vào mảng biến phiên có tên là $ _SESSION ['userPermissions'].) Nếu quyền hiện tại nằm trong mảng quyền của người dùng, điều đó có nghĩa là người dùng đó có quyền đó và do đó hàm trả về true, nếu không thì trả về false.
Bây giờ, nếu bạn muốn kiểm tra xem người dùng có quyền hay không, hãy nói quyền xuất bản bài đăng mà bạn phải làm là gọi phương thức canPublishPost () như sau:
<?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 ?>
Cũng như một phần mềm trung gian, trước khi chúng tôi cập nhật một bài đăng, trước tiên chúng tôi sẽ gọi hàm phần mềm trung gian canUpdatePost (). Nếu chức năng kiểm tra và thấy rằng người dùng không có quyền cập nhật bài đăng, nó sẽ trả về false và sau đó chúng tôi có thể chuyển hướng họ đến trang chủ với thông báo cho biết anh ta không được phép cập nhật bài đăng. Như thế này:
// 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
}
}
Điều tương tự đối với việc xuất bản / hủy xuất bản bài đăng:
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
}
Bây giờ chúng ta còn lại với phần cuối cùng của hướng dẫn này là cập nhật hồ sơ người dùng và cũng cấp cho người dùng đã đăng ký khả năng xóa tài khoản của chính họ.
Cảm ơn vì đã theo dõi. Nếu bạn có bất cứ điều gì để nói, vui lòng để lại trong phần bình luận.