Questa è la parte 5 di una serie su come creare un sistema di gestione degli account utente in PHP. Puoi trovare le altre parti qui:parte 1, parte 2, parte 3 e parte 4.
Abbiamo finito di gestire gli account utente amministrativi nell'ultima sezione e i ruoli. In questa parte, analizzeremo la creazione delle autorizzazioni e l'assegnazione e l'annullamento dell'assegnazione delle autorizzazioni ai ruoli utente.
Assegnazione delle autorizzazioni ai ruoli
Come ho detto nella prima parte di questa serie, i ruoli sono correlati alle autorizzazioni in una relazione Molti-a-molti. Un ruolo può avere molte autorizzazioni e un'autorizzazione può appartenere a molti ruoli.
Abbiamo già creato la tabella dei ruoli. Ora creeremo una tabella dei permessi per mantenere i permessi e una terza tabella chiamata permit_role per contenere le informazioni sulla relazione tra i ruoli e la tabella dei permessi.
Crea le due tabelle per avere le seguenti proprietà:
tabella delle autorizzazioni:
CREATE TABLE `permissions` (
`id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` varchar(255) NOT NULL UNIQUE KEY,
`description` text NOT NULL
)
tabella permesso_ruolo:
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`)
)
Nella tabella permit_role, role_id fa riferimento all'id del ruolo nella tabella dei ruoli mentre permit_id fa riferimento alla colonna dell'autorizzazione all'id nella tabella delle autorizzazioni. Per assegnare un'autorizzazione a un ruolo, lo facciamo semplicemente inserendo un record di tale permit_id contro role_id nella tabella permit_role e la relazione viene stabilita. Ciò significa che se vogliamo annullare l'assegnazione di tale autorizzazione da quel ruolo, eliminiamo semplicemente il record di quel role_id rispetto a quel permit_id su questa tabella di permit_role.
Le ultime due righe della query SQL di cui sopra sono vincoli che garantiscono che quando un particolare ruolo o autorizzazione viene eliminato, tutte le voci nella tabella permit_role con l'ID di tale autorizzazione o quell'ID ruolo verranno automaticamente eliminate dal database. Lo facciamo perché non vogliamo che la tabella permit_role conservi le informazioni sulla relazione su un ruolo o su un'autorizzazione che non esiste più.
Puoi anche impostare questi vincoli manualmente usando PHPMyAdmin:puoi farlo sull'interfaccia semplicemente selezionando la tabella permit_role e andando su Vista relazionale> scheda Struttura e semplicemente compilando i valori. Se ancora non riesci a farlo, lascia un commento qui sotto e cercherò di aiutarti.
Ora la relazione è stabilita.
Creiamo una pagina per assegnare le autorizzazioni a un ruolo. Nella nostra pagina roleList.php, elenchiamo i vari ruoli con un pulsante "permessi" accanto a ciascuno. Facendo clic su questo collegamento ci porterà a una pagina chiamata assignPermissions.php. Creiamo quel file ora nella cartella admin/ruoli.
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>
Facendo clic sul pulsante "autorizzazioni" di un ruolo si accede a questa pagina. Ma in questo momento se fai clic su di esso e arrivi a questa pagina assignPermissions.php, c'è un messaggio di errore che dice che le funzioni getAllPermissions() non sono definite. Prima di aggiungere questo metodo, esaminiamo come implementiamo effettivamente questa assegnazione e non assegnazione dei permessi nel nostro codice PHP.
Quando fai clic sul pulsante "autorizzazioni" di un ruolo, vieni indirizzato alla pagina assignPermissions.php con l'ID di quel ruolo. Ma prima di visualizzare la pagina di assegnazione delle autorizzazioni, utilizziamo l'ID del ruolo per recuperare tutte le autorizzazioni che sono già state assegnate a quel ruolo dal database. E poi tiriamo fuori anche tutti i permessi disponibili nella tabella dei permessi. Ora abbiamo due array di permessi:quelli che sono stati assegnati a un ruolo e tutti i permessi disponibili nel nostro database. Il primo è un sottoinsieme del secondo.
Assegnare un'autorizzazione a un ruolo significa aggiungere quell'autorizzazione dall'elenco generale di autorizzazioni all'array di autorizzazioni appartenenti a quel ruolo e salvare l'intera informazione nella tabella permit_role. Annullare l'assegnazione di un'autorizzazione a un ruolo significa rimuovere quella particolare autorizzazione dall'elenco delle autorizzazioni che appartengono a quel ruolo.
La nostra logica è quella di scorrere un array di tutte le autorizzazioni disponibili dal database, quindi per ciascuno dei loro ID determiniamo se tale ID è già nell'array di ID per le autorizzazioni del ruolo. se esiste, significa che il ruolo ha già tale autorizzazione, quindi lo mostriamo insieme a una casella di controllo selezionata. Se non esiste, lo mostriamo insieme a una casella di controllo deselezionata.
Dopo che tutto è stato visualizzato, fare clic su una casella di controllo selezionata significa annullare l'assegnazione dell'autorizzazione mentre fare clic su una casella di controllo non selezionata significa assegnare l'autorizzazione al ruolo. Dopo aver eseguito tutte le operazioni di controllo e deselezionamento, l'utente fa clic sul pulsante "Salva autorizzazioni" sotto la tabella per salvare tutte le autorizzazioni che sono state selezionate per quel ruolo.
Aggiungiamo tutte queste funzioni al file roleLogic.php. Sono:
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);
}
Mettere in funzione i permessi
A questo punto, possiamo determinare qual è il ruolo di un utente e poiché il ruolo è correlato alle autorizzazioni, possiamo quindi conoscere anche le loro autorizzazioni.
Ora vogliamo mettere in funzione queste autorizzazioni: vale a dire assicurare che un utente amministratore sia autorizzato a eseguire solo le azioni per le quali dispone delle autorizzazioni. Otterremo questo utilizzando le funzioni del middleware. Un middleware è fondamentalmente un pezzo di codice o una funzione che viene eseguita prima che venga eseguita un'azione. In genere, questa funzione del middleware può modificare il comportamento dell'azione o eseguire alcuni controlli che potrebbero finire per interrompere del tutto l'azione a seconda dei risultati del controllo.
Ad esempio, un utente può disporre delle autorizzazioni create-post, update-post e delete-post. Se hanno effettuato l'accesso e tentano di pubblicare un post, la nostra funzione middleware verifica prima se questo utente dispone dell'autorizzazione di pubblicazione del post. Se hanno questa autorizzazione, la nostra funzione middleware restituirà true e il post verrà pubblicato. Se non hanno l'autorizzazione per pubblicare post, la nostra funzione middleware li reindirizzerà indietro con un messaggio che dice che non hanno l'autorizzazione per pubblicare il post.
Metteremo tutte le nostre funzioni middleware in un unico file chiamato middleware.php. Crealo ora nella cartella admin e incollaci questo codice:
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;
}
}
?>
"; morire(); restituisce vero; } else { return false; } } funzione canDeletePost() { if(in_array('delete-post', $_SESSION['userPermissions'])){ return true; } else { return false; } } funzione 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($id_utente, $id_post) { if(in_array('delete-role', $_SESSION['userPermissions'])){ return true; } else { return false; } }?> La prima istruzione if verifica se l'utente ha effettuato l'accesso. Se l'utente non ha effettuato l'accesso, verrà reindirizzato alla home page. La seconda istruzione if verifica se l'utente è loggato e se ha un ruolo (è admin). Se si scopre che l'utente è loggato e ha un ruolo, accederà alla pagina, altrimenti verrà reindirizzato alla home page.
In ogni file in cui desideri limitare l'accesso agli utenti non amministratori, dovresti semplicemente includere questo file middleware.php in quel file. Quindi includeremo questo file in tutti i nostri file di amministrazione a cui non vogliamo che gli utenti normali accedano. Quindi apri tutti i file nelle due cartelle all'interno della cartella admin ovvero:utenti, ruoli. In ciascuno dei file, aggiungi la riga seguente appena sotto l'inclusione per config.php.
Così:
<?php include('../../config.php'); ?>
<?php require_once '../middleware.php'; ?>
E questo reindirizzerà qualsiasi utente non amministratore che tenta di visitare la pagina.
Anche in questo file middleware.php, utilizziamo in_array() di PHP per verificare se l'autorizzazione che stiamo testando è nell'array delle autorizzazioni di quell'utente. (Quando un utente amministratore effettua l'accesso, inseriamo tutti i suoi permessi in un array di variabili di sessione chiamato $_SESSION['userPermissions'].) Se l'autorizzazione corrente è nell'array dei permessi dell'utente, significa che quell'utente ha quell'autorizzazione e quindi la funzione restituisce true, altrimenti restituisce false.
Ora, se vuoi controllare se un utente ha un'autorizzazione, supponi che un'autorizzazione per pubblicare post che devi fare è chiamare il metodo canPublishPost() in questo modo:
<?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 ?>
Anche come middleware, prima di aggiornare un post, chiameremo la funzione middleware canUpdatePost(). Se la funzione verifica e vede che l'utente non dispone dell'autorizzazione per l'aggiornamento del post, restituirà false e possiamo quindi reindirizzarlo alla home page con un messaggio che dice che non è autorizzato ad aggiornare il post. In questo modo:
// 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
}
}
Stessa cosa per pubblicare/annullare 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
}
Ora ci rimane l'ultima parte di questo tutorial che aggiorna il profilo utente e offre anche agli utenti registrati la possibilità di eliminare i propri account.
Grazie per aver seguito. Se hai qualcosa da dire, lascialo nei commenti.