Dit is deel 5 van een serie over het maken van een beheersysteem voor gebruikersaccounts in PHP. De andere delen vind je hier:deel1, deel2, deel 3 en deel 4.
We zijn klaar met het beheren van beheerdersaccounts in de laatste sectie, evenals met rollen. In dit deel gaan we door met het maken van machtigingen en het toewijzen en intrekken van de machtigingen aan gebruikersrollen.
Permissies toewijzen aan rollen
Zoals ik in het eerste deel van deze serie al zei, zijn rollen gerelateerd aan machtigingen in een Veel-op-Veel-relatie. Een rol kan veel machtigingen hebben en een machtiging kan bij veel rollen horen.
We hebben de rollentabel al gemaakt. Nu gaan we een tabel met machtigingen maken om machtigingen te bewaren en een derde tabel met de naam permission_role om de informatie over de relatie tussen de rollen en de tabel met machtigingen te bewaren.
Maak de twee tabellen met de volgende eigenschappen:
machtigingentabel:
CREATE TABLE `permissions` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` varchar(255) NOT NULL UNIQUE KEY,
`description` text NOT NULL
)
permission_role tabel:
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`)
)
In de tabel permission_role verwijst de role_id naar de rol-ID in de tabel met rollen, terwijl de permission_id verwijst naar de kolom met de machtigingen-ID in de tabel met rechten. Om een permissie aan een rol toe te kennen, doen we dat door simpelweg een record van die permission_id in te voegen tegen de role_id in de tabel permission_role en de relatie wordt tot stand gebracht. Dit betekent dat als we de toewijzing van die machtiging aan die rol willen opheffen, we gewoon de record van die role_id tegen die permission_id in deze permission_role-tabel verwijderen.
De laatste twee regels van de bovenstaande SQL-query zijn beperkingen die ervoor zorgen dat wanneer een bepaalde rol of machtiging wordt verwijderd, alle vermeldingen in de tabel permission_role met de machtigings-ID of die rol-ID ook automatisch door de database worden verwijderd. We doen dit omdat we niet willen dat de tabel permission_role relatiegegevens bevat over een rol of een machtiging die niet meer bestaat.
U kunt deze beperkingen ook handmatig instellen met behulp van PHPMyAdmin:u kunt dit eenvoudig in de interface doen door de tabel permission_role te selecteren en naar Relationele weergave> tabblad Structuur te gaan en de waarden in te vullen. Als je dit nog steeds niet kunt doen, laat dan hieronder een reactie achter en ik zal proberen je te helpen.
Nu is de relatie gezet.
Laten we een pagina maken om machtigingen aan een rol toe te wijzen. Op onze roleList.php-pagina zetten we de verschillende rollen op een rij met een 'permissions'-knop ernaast. Als u op deze link klikt, gaan we naar een pagina met de naam assignPermissions.php. Laten we dat bestand nu in de map admin/rollen maken.
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>
Als je op de 'permissions'-knop van een rol klikt, kom je op deze pagina terecht. Maar als u er nu op klikt en naar deze assignPermissions.php-pagina komt, is er een foutmelding dat de functies getAllPermissions() niet gedefinieerd zijn. Voordat we deze methode toevoegen, laten we eens kijken hoe we dit toewijzen en niet-toekennen van toestemming daadwerkelijk implementeren in onze PHP-code.
Wanneer u op de 'permissions'-knop van een rol klikt, wordt u naar de assignPermissions.php-pagina gebracht met het id van die rol. Maar voordat we de pagina met rechten toewijzen, gebruiken we de rol-ID om alle rechten op te halen die al aan die rol zijn toegewezen uit de database. En dan brengen we ook alle machtigingen naar voren die beschikbaar zijn in de machtigingentabel. Nu hebben we twee reeksen machtigingen:de machtigingen die zijn toegewezen aan een rol en alle machtigingen die beschikbaar zijn in onze database. Een eerste is een subset van de laatste.
Een machtiging toewijzen aan een rol betekent dat u die machtiging uit de algemene lijst met machtigingen toevoegt aan de reeks machtigingen die bij die rol horen en dat deze informatie in zijn geheel wordt opgeslagen in de tabel permission_role. Als u de toewijzing van een machtiging aan een rol ongedaan maakt, moet u die specifieke machtiging verwijderen uit de lijst met machtigingen die bij die rol horen.
Onze logica is om een reeks van alle beschikbare machtigingen uit de database te doorlopen, en voor elk van hun id's bepalen we of die id al in de reeks id's voor de machtigingen van de rol staat. als het bestaat, betekent dit dat de rol die toestemming al heeft, dus we geven het weer naast een aangevinkt selectievakje. Als het niet bestaat, geven we het weer naast een niet-aangevinkt selectievakje.
Nadat alles is weergegeven, betekent het klikken op een aangevinkt selectievakje dat de machtiging ongedaan wordt gemaakt, terwijl het klikken op een niet-aangevinkt selectievakje betekent dat de machtiging aan de rol wordt toegewezen. Nadat al het aan- en uitvinken is voltooid, klikt de gebruiker op de knop 'Machtigingen opslaan' onder de tabel om alle aangevinkte machtigingen voor die rol op te slaan.
Laten we al deze functies toevoegen aan het bestand roleLogic.php. Dit zijn:
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);
}
De rechten aan het werk zetten
Op dit punt kunnen we bepalen wat de rol van een gebruiker is en aangezien de rol gerelateerd is aan machtigingen, kunnen we daarom ook hun machtigingen kennen.
Nu willen we deze rechten aan het werk zetten:dat wil zeggen, om ervoor te zorgen dat een beheerder alleen die acties mag uitvoeren waarvoor hij de rechten heeft. We zullen dit bereiken met behulp van middleware-functies. Een middleware is in feite een stukje code of een functie die wordt uitgevoerd voordat een actie wordt uitgevoerd. Doorgaans kan deze middlewarefunctie het gedrag van de actie wijzigen of enkele controles uitvoeren die de actie uiteindelijk helemaal kunnen stoppen, afhankelijk van de resultaten van de controle.
Een gebruiker kan bijvoorbeeld de machtigingen maken-post, update-post en delete-post hebben. Als ze zijn ingelogd en proberen een bericht te publiceren, controleert onze middleware-functie eerst of deze gebruiker toestemming heeft om een bericht te publiceren. Als ze deze toestemming hebben, zal onze middleware-functie true retourneren en wordt het bericht gepubliceerd. Als ze geen toestemming hebben om het bericht te publiceren, zal onze middleware-functie ze terugsturen met een bericht dat ze niet de toestemming hebben om het bericht te publiceren.
We zullen al onze middleware-functies in een enkel bestand plaatsen met de naam middleware.php. Maak het nu aan in de map admin en plak deze code erin:
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;
}
}
?>
"; dood gaan(); retourneer waar; } 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; } }?> Het eerste if-statement controleert of de gebruiker is ingelogd. Als de gebruiker niet is ingelogd, wordt deze doorgestuurd naar de homepage. Het tweede if-statement controleert of de gebruiker is ingelogd en of hij/zij een rol heeft (admin is). Als blijkt dat de gebruiker is ingelogd en een rol heeft, krijgt hij toegang tot de pagina, anders wordt hij teruggestuurd naar de startpagina.
In elk bestand waarvan u de toegang door niet-beheerders wilt beperken, moet u dit middleware.php-bestand in dat bestand opnemen. Dus al onze admin-bestanden waarin we niet willen dat normale gebruikers toegang hebben, we zullen dit bestand erin opnemen. Open dus alle bestanden in de twee mappen in de beheerdersmap, namelijk:gebruikers, rollen. Voeg in elk van de bestanden de volgende regel net onder de include voor config.php toe.
Vind ik leuk:
<?php include('../../config.php'); ?>
<?php require_once '../middleware.php'; ?>
En dat zal elke niet-beheerder die de pagina probeert te bezoeken, omleiden.
Ook in dit middleware.php-bestand gebruiken we PHP's in_array() om te controleren of de toestemming die we testen zich in de reeks van de toestemmingen van die gebruiker bevindt. (Wanneer een admin-gebruiker inlogt, plaatsen we al zijn rechten in een sessievariabele array genaamd $_SESSION['userPermissions'].) Als de huidige toestemming in de array van de gebruikersrechten staat, betekent dit dat die gebruiker die toestemming heeft en daarom retourneert de functie waar, anders retourneert het onwaar.
Als je nu wilt controleren of een gebruiker toestemming heeft, zeg een publicatie-post toestemming die je moet doen door de methode canPublishPost() als volgt aan te roepen:
<?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 ?>
Ook als middleware zullen we, voordat we een bericht bijwerken, eerst de middleware-functie canUpdatePost() aanroepen. Als de functie controleert en ziet dat de gebruiker niet over de update-post-toestemming beschikt, zal deze false retourneren en kunnen we ze doorverwijzen naar de startpagina met een bericht dat hij niet is toegestaan om de post bij te werken. Zoals dit:
// 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
}
}
Hetzelfde geldt voor het publiceren/depubliceren van berichten:
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
}
Nu blijven we over met het laatste deel van deze tutorial, namelijk het bijwerken van het gebruikersprofiel en het geven van geregistreerde gebruikers de mogelijkheid om hun eigen accounts te verwijderen.
Bedankt voor het volgen. Als je iets te zeggen hebt, laat het dan in de reacties achter.