Mysql
 sql >> Baza danych >  >> RDS >> Mysql

Zarządzanie kontami użytkowników, role, uprawnienia, uwierzytelnianie PHP i MySQL -- Część 5

To jest część 5 serii poświęconej tworzeniu systemu zarządzania kontami użytkowników w PHP. Pozostałe części znajdziesz tutaj:część 1, część 2, część 3 i część 4.

W ostatniej sekcji zakończyliśmy zarządzanie kontami użytkowników administracyjnych oraz rolami. W tej części przejdziemy przez tworzenie uprawnień oraz przypisywanie i anulowanie przypisywania uprawnień do ról użytkowników.

Przypisywanie uprawnień do ról

Jak powiedziałem w pierwszej części tej serii, role są powiązane z uprawnieniami w relacji wiele-do-wielu. Rola może mieć wiele uprawnień, a uprawnienia mogą należeć do wielu ról.

Stworzyliśmy już tabelę ról. Teraz utworzymy tabelę uprawnień do przechowywania uprawnień i trzecią tabelę o nazwie permission_role do przechowywania informacji o relacji między rolami a tabelą uprawnień.

Utwórz dwie tabele, aby miały następujące właściwości:

tabela uprawnień:

CREATE TABLE `permissions` (
 `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
 `name` varchar(255) NOT NULL UNIQUE KEY,
 `description` text NOT NULL
)

tabela ról uprawnień:

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`)
)

W tabeli permission_role parametr role_id odwołuje się do identyfikatora roli w tabeli ról, a parametr permission_id odwołuje się do kolumny identyfikatora uprawnienia w tabeli uprawnień. Aby przypisać uprawnienie do roli, robimy to przez proste wstawienie rekordu tego uprawnienia_id względem roli_id w tabeli uprawnieni_role i nawiązanie relacji. Oznacza to, że jeśli chcemy cofnąć przypisanie tego uprawnienia do tej roli, po prostu usuwamy rekord tego identyfikatora roli względem tego identyfikatora uprawnienia w tej tabeli uprawnień_roli.

Ostatnie dwa wiersze powyższego zapytania SQL to ograniczenia, które zapewniają, że po usunięciu określonej roli lub uprawnienia wszystkie wpisy w tabeli permission_role z identyfikatorem tego uprawnienia lub identyfikatorem roli również zostaną automatycznie usunięte przez bazę danych. Robimy to, ponieważ nie chcemy, aby tabela permission_role zawierała informacje o relacjach dotyczących roli lub uprawnienia, które już nie istnieje.

Możesz również ustawić te ograniczenia ręcznie za pomocą PHPMyAdmin:możesz to zrobić w interfejsie, po prostu wybierając tabelę permission_role i przechodząc do zakładki Widok relacyjny> Struktura i po prostu wypełniając wartości. Jeśli nadal nie możesz tego zrobić, zostaw komentarz poniżej, a postaram się Ci pomóc.

Teraz związek jest ustalony.

Stwórzmy stronę, aby przypisać uprawnienia do roli. Na naszej stronie roleList.php wymieniamy różne role z przyciskiem „uprawnienia” obok każdej z nich. Kliknięcie tego linku przeniesie nas na stronę o nazwie assignPermissions.php. Utwórzmy teraz ten plik w folderze 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>

Kliknięcie przycisku „uprawnienia” roli prowadzi do tej strony. Ale teraz, jeśli klikniesz na nią i przejdziesz do tej strony assignPermissions.php, pojawi się komunikat o błędzie mówiący, że funkcje getAllPermissions() są niezdefiniowane. Zanim dodamy tę metodę, przyjrzyjmy się, jak faktycznie zaimplementujemy to przypisywanie i cofanie uprawnień w naszym kodzie PHP.

Kiedy klikniesz przycisk „uprawnienia” roli, zostaniesz przeniesiony na stronę assignPermissions.php z identyfikatorem tej roli. Jednak przed wyświetleniem strony przypisywania uprawnień używamy identyfikatora roli, aby pobrać z bazy danych wszystkie uprawnienia, które zostały już przypisane do tej roli. Następnie wyświetlamy również wszystkie uprawnienia dostępne w tabeli uprawnień. Teraz mamy dwie tablice uprawnień:te, które zostały przypisane do roli oraz wszystkie uprawnienia dostępne w naszej bazie danych. Jeden pierwszy jest podzbiorem drugiego.

Przypisanie uprawnienia do roli oznacza dodanie tego uprawnienia z ogólnej listy uprawnień do tablicy uprawnień należących do tej roli i zapisanie wszystkich tych informacji w tabeli permission_role. Cofnięcie przypisania uprawnienia do roli oznacza usunięcie tego konkretnego uprawnienia z listy uprawnień należących do tej roli.

Naszą logiką jest przejście przez tablicę wszystkich dostępnych uprawnień z bazy danych, a następnie dla każdego ich identyfikatora określamy, czy ten identyfikator jest już w tablicy identyfikatorów uprawnień roli. jeśli istnieje, oznacza to, że rola ma już to uprawnienie, więc wyświetlamy je obok zaznaczonego pola wyboru. Jeśli nie istnieje, wyświetlamy go obok niezaznaczonego pola wyboru.

Po wyświetleniu wszystkiego kliknięcie w zaznaczone pole wyboru oznacza cofnięcie przypisania uprawnień, natomiast kliknięcie w niezaznaczone pole wyboru oznacza przypisanie uprawnień do roli. Po zakończeniu wszystkich sprawdzeń i odznaczeń użytkownik klika przycisk „Zapisz uprawnienia” pod tabelą, aby zapisać wszystkie uprawnienia, które zostały sprawdzone w tej roli.

Dodajmy wszystkie te funkcje do pliku roleLogic.php. Są to:

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);
  }

Oddanie uprawnień do pracy

W tym momencie możemy określić, jaka jest rola użytkownika, a ponieważ rola jest powiązana z uprawnieniami, możemy zatem również poznać ich uprawnienia.

Teraz chcemy sprawić, by te uprawnienia działały, to znaczy zapewnić, że administrator może wykonywać tylko te czynności, do których ma uprawnienia. Osiągniemy to za pomocą funkcji oprogramowania pośredniego. Oprogramowanie pośredniczące to w zasadzie fragment kodu lub funkcja, która jest wykonywana przed wykonaniem akcji. Zazwyczaj ta funkcja oprogramowania pośredniego może modyfikować zachowanie akcji lub wykonywać pewne sprawdzenia, które mogą zakończyć się całkowitym zatrzymaniem akcji w zależności od wyników sprawdzenia.

Na przykład użytkownik może mieć uprawnienia do tworzenia publikowania, aktualizowania publikowania i usuwania publikowania. Jeśli są zalogowani i próbują opublikować post, nasza funkcja oprogramowania pośredniczącego najpierw sprawdza, czy ten użytkownik ma uprawnienia do publikowania postów. Jeśli mają takie uprawnienia, nasza funkcja oprogramowania pośredniczącego zwróci true i post zostanie opublikowany. Jeśli nie mają uprawnień do publikowania postów, nasza funkcja oprogramowania pośredniego przekieruje ich z powrotem z komunikatem, że nie mają uprawnień do publikowania postów.

Umieścimy wszystkie nasze funkcje oprogramowania pośredniego w jednym pliku o nazwie middleware.php. Utwórz go teraz w folderze admin i wklej do niego ten kod:

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;
    }
  }
?>
"; umierać(); zwróć prawdę; } 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; } }?>

Pierwsza instrukcja if sprawdza, czy użytkownik jest zalogowany. Jeśli użytkownik nie jest zalogowany, zostanie przekierowany na stronę główną. Druga instrukcja if sprawdza, czy użytkownik jest zalogowany i czy ma przypisaną rolę (jest administratorem). Jeśli okaże się, że użytkownik jest zalogowany i ma przypisaną rolę, uzyska dostęp do strony, w przeciwnym razie zostanie przekierowany z powrotem na stronę główną.

W każdym pliku, do którego chcesz ograniczyć dostęp użytkownikom niebędącym administratorami, powinieneś po prostu dołączyć ten plik middleware.php do tego pliku. Tak więc wszystkie nasze pliki administracyjne, do których nie chcemy, aby zwykli użytkownicy mieli dostęp, umieścimy w nich ten plik. Więc otwórz wszystkie pliki w dwóch folderach w folderze administratora, a mianowicie:użytkownicy, role. W każdym z plików dodaj następujący wiersz tuż poniżej dołączenia dla config.php.

Tak:

<?php include('../../config.php'); ?>
<?php require_once '../middleware.php'; ?>

A to przekieruje każdego użytkownika niebędącego administratorem, który spróbuje odwiedzić stronę.

Również w tym pliku middleware.php używamy funkcji in_array() w PHP, aby sprawdzić, czy testowane przez nas uprawnienie znajduje się w tablicy uprawnień tego użytkownika. (Gdy loguje się administrator, umieszczamy wszystkie jego uprawnienia w tablicy zmiennych sesji o nazwie $_SESSION['userPermissions'].) Jeśli bieżące uprawnienie znajduje się w tablicy uprawnień użytkownika, oznacza to, że ten użytkownik ma to uprawnienie i dlatego funkcja zwraca prawdę, w przeciwnym razie zwraca fałsz.

Teraz, jeśli chcesz sprawdzić, czy użytkownik ma uprawnienia, powiedzmy, że uprawnienie do publikowania postów, które musisz zrobić, to wywołanie metody canPublishPost() w następujący sposób:

<?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 ?>

Również jako oprogramowanie pośrednie, zanim zaktualizujemy post, najpierw wywołamy funkcję oprogramowania pośredniego canUpdatePost(). Jeśli funkcja sprawdzi i zobaczy, że użytkownik nie ma uprawnień do publikowania aktualizacji, zwróci false i wtedy możemy przekierować go na stronę główną z komunikatem, że nie może aktualizować wpisu. Tak:

// 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
  }
}

To samo dotyczy publikowania/cofania publikowania postów:

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

}

Teraz pozostała ostatnia część tego samouczka, która aktualizuje profil użytkownika, a także daje zarejestrowanym użytkownikom możliwość usuwania własnych kont.

Dziękuję za śledzenie. Jeśli masz coś do powiedzenia, zostaw to w komentarzach.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zrozumienie nowej fali upałów MySQL

  2. PHP i mySQL:Rok 2038 Błąd:Co to jest? Jak to rozwiązać?

  3. Jak zaplanować zapytanie MySQL?

  4. Dowiedz się, jak wykonać kopię zapasową bazy danych MySQL

  5. Czy dynamiczne zapytania mysql z kodem ucieczki sql są tak samo bezpieczne, jak przygotowane instrukcje?