Det här är del 5 i en serie om hur man skapar ett hanteringssystem för användarkonton i PHP. Du hittar de andra delarna här:del1, del2, del 3 och del 4.
Vi avslutade med att hantera administrativa användarkonton i det sista avsnittet samt roller. I den här delen kommer vi att gå igenom att skapa behörigheter och tilldela och ta bort behörigheterna till användarroller.
Tilldela behörigheter till roller
Som jag sa i den första delen av den här serien är roller relaterade till behörigheter i en Många-till-många-relation. En roll kan ha många behörigheter och en behörighet kan tillhöra många roller.
Vi har redan skapat rolltabellen. Nu kommer vi att skapa en behörighetstabell för behörigheter och en tredje tabell som heter permission_role för att innehålla informationen om förhållandet mellan roller och behörighetstabeller.
Skapa de två tabellerna för att ha följande egenskaper:
behörighetstabell:
CREATE TABLE `permissions` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` varchar(255) NOT NULL UNIQUE KEY,
`description` text NOT NULL
)
behörighetsrolltabell:
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`)
)
I tabellen permission_role refererar role_id till roll-id i rolls-tabellen medan permission_id refererar till behörighets-id-kolumnen i behörighetstabellen. För att tilldela en behörighet till en roll, gör vi det genom att helt enkelt infoga en post för det behörighets-id mot role_id i tabellen permission_role och relationen upprättas. Detta innebär att om vi vill ta bort den behörigheten från den rollen, tar vi bara bort posten för det role_id mot det permission_id i denna permission_role-tabell.
De två sista raderna i SQL-frågan ovan är begränsningar som säkerställer att när en viss roll eller behörighet tas bort, kommer alla poster i tabellen permission_role som har den behörighetens id eller det roll-id också automatiskt att raderas av databasen. Vi gör detta för att vi inte vill att tabellen permission_role innehåller relationsinformation om en roll eller en behörighet som inte längre finns.
Du kan också ställa in dessa begränsningar manuellt med PHPMyAdmin:du kan göra det i gränssnittet helt enkelt genom att välja tabellen permission_role och gå till Relationsvy> Strukturfliken och bara fylla i värdena. Om du fortfarande inte kan göra detta, lämna en kommentar nedan så ska jag försöka hjälpa dig.
Nu är förhållandet satt.
Låt oss skapa en sida för att tilldela behörigheter till en roll. På vår roleList.php-sida listar vi de olika rollerna med en "behörighetsknapp" bredvid var och en. Genom att klicka på den här länken kommer vi till en sida som heter assignPermissions.php. Låt oss skapa den filen nu i mappen admin/roller.
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>
Genom att klicka på knappen "behörigheter" för en roll kommer du till den här sidan. Men just nu om du klickar på den och kommer till den här assignPermissions.php-sidan, finns det ett felmeddelande som säger att getAllPermissions()-funktionerna är odefinierade. Innan vi lägger till den här metoden, låt oss gå igenom hur vi faktiskt implementerar denna tilldelning och avtilldelning av behörighet i vår PHP-kod.
När du klickar på "behörigheter"-knappen för en roll, kommer du till sidan assignPermissions.php med rollens ID. Men innan vi visar sidan tilldela behörigheter använder vi roll-id för att hämta alla behörigheter som redan har tilldelats den rollen från databasen. Och då tar vi också fram alla behörigheter som finns tillgängliga i behörighetstabellen. Nu har vi två arrayer av behörigheter:de som har tilldelats en roll och alla behörigheter som finns tillgängliga i vår databas. En förra är en delmängd av den senare.
Att tilldela en behörighet till en roll innebär att du lägger till den behörigheten från den övergripande listan över behörigheter till arrayen av behörigheter som hör till den rollen och sparar hela denna information i tabellen permission_role. Att ta bort en behörighet från en roll innebär att man tar bort den specifika behörigheten från listan över behörigheter som hör till den rollen.
Vår logik är att gå igenom en array av alla tillgängliga behörigheter från databasen, och sedan för vart och ett av deras id bestämmer vi om det id:t redan finns i arrayen av id för rollens behörigheter. om det finns betyder det att rollen redan har den behörigheten så vi visar den bredvid en kryssruta. Om det inte finns visar vi det bredvid en omarkerad kryssruta.
När allt har visats betyder att klicka på en markerad kryssruta att du avaktiverar behörigheten medan att klicka på en omarkerad kryssruta innebär att du tilldelar behörigheten till rollen. När all kontroll och avmarkering är gjord klickar användaren sedan på knappen "Spara behörigheter" under tabellen för att spara alla behörigheter som har kontrollerats till den rollen.
Låt oss lägga till alla dessa funktioner i filen roleLogic.php. De är:
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);
}
Sätta behörigheterna att fungera
Vid det här laget kan vi avgöra vad en användares roll är och eftersom rollen är relaterad till behörigheter kan vi därför också känna till deras behörigheter.
Nu vill vi använda dessa behörigheter: det vill säga försäkra att en administratörsanvändare endast tillåts utföra de åtgärder som han har behörighet för. Vi kommer att uppnå detta med hjälp av middleware-funktioner. En middleware är i grunden en bit kod eller en funktion som exekveras innan en åtgärd utförs. Vanligtvis kan denna mellanprogramsfunktion ändra åtgärdens beteende eller utföra vissa kontroller som kan sluta med att åtgärden stoppas helt beroende på resultatet av kontrollen.
En användare kan till exempel ha behörigheterna create-post, update-post och delete-post. Om de är inloggade och de försöker publicera ett inlägg, kontrollerar vår middleware-funktion först om den här användaren har tillståndet att publicera inlägg. Om de har denna behörighet kommer vår middleware-funktion att returnera sant och inlägget kommer att publiceras. Om de saknar behörighet att publicera inlägg kommer vår mellanprogramfunktion att omdirigera dem tillbaka med ett meddelande som säger att de inte har tillstånd att publicera inlägget.
Vi kommer att lägga alla våra middleware-funktioner i en enda fil som heter middleware.php. Skapa den nu i mappen admin och klistra in den här koden i den:
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;
}
}
?>
"; dö(); returnera sant; } else { return false; } } funktion canDeletePost() { if(in_array('delete-post', $_SESSION['userPermissions'])){ return true; } else { return false; } } funktion canCreateUser() { if(in_array('create-user', $_SESSION['userPermissions'])){ return true; } else { return false; } } funktion canUpdateUser() { if(in_array('update-user', $_SESSION['userPermissions'])){ return true; } else { return false; } } funktion canDeleteUser() { if(in_array('delete-user', $_SESSION['userPermissions'])){ return true; } else { return false; } } funktion canCreateRole($role_id) { if(in_array('create-role', $_SESSION['userPermissions'])){ return true; } else { return false; } } funktion canUpdateRole($role_id) { if(in_array('update-role', $_SESSION['userPermissions'])){ return true; } else { return false; } } funktion canDeleteRole($user_id, $post_id) { if(in_array('delete-role', $_SESSION['userPermissions'])){ return true; } else { return false; } }?> Den första if-satsen kontrollerar om användaren är inloggad. Om användaren inte är inloggad kommer de att omdirigeras till hemsidan. Den andra if-satsen kontrollerar om användaren är inloggad och om han/hon har en roll (är admin). Om användaren visar sig vara inloggad och har en roll kommer de att komma åt sidan, annars omdirigeras den tillbaka till hemsidan.
I varje fil där du vill begränsa icke-adminanvändare från att komma åt, bör du bara inkludera filen middleware.php i den filen. Så alla våra administratörsfiler som vi inte vill att normala användare ska få tillgång till kommer vi att inkludera den här filen i dem. Så öppna alla filer i de två mapparna i admin-mappen nämligen:användare, roller. I var och en av filerna lägger du till följande rad precis nedanför include för config.php.
Som så:
<?php include('../../config.php'); ?>
<?php require_once '../middleware.php'; ?>
Och det kommer att omdirigera alla icke-administratörer som försöker besöka sidan.
Också i den här middleware.php-filen använder vi PHP:s in_array() för att kontrollera om behörigheten vi testar finns i arrayen med den användarens behörigheter. (När en administratörsanvändare loggar in lägger vi all deras behörighet i en sessionsvariabel array som heter $_SESSION['userPermissions'].) Om den aktuella behörigheten finns i arrayen av användarens behörigheter, betyder det att den användaren har den behörigheten och därför returnerar funktionen true, annars returnerar den false.
Om du nu vill kontrollera om en användare har en behörighet, säg att en publiceringsbehörighet du måste göra är att anropa metoden canPublishPost() så här:
<?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 ?>
Också som mellanprogram, innan vi uppdaterar ett inlägg, anropar vi först funktionen canUpdatePost() mellanprogram. Om funktionen kontrollerar och ser att användaren inte har tillståndet att uppdatera inlägget kommer den att returnera falskt och vi kan sedan omdirigera dem till hemsidan med ett meddelande som säger att han inte får uppdatera inlägget. Så här:
// 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
}
}
Samma sak för att publicera/avpublicera inlägg:
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 är vi kvar med den sista delen av denna handledning som är att uppdatera användarprofilen och även ger registrerade användare möjligheten att ta bort sina egna konton.
Tack för att du följde med. Om du har något att säga, skriv det i kommentarerna.