Сегодня мы реализуем форму регистрации, входа, выхода и обновления учётной записи пользователя, используя JSON Web Token
  1. Что такое JWT?
  2. Файловая структура
  3. Настройка базы данных
  4. Создание API для регистрации пользователей
  5. Создание API для входа пользователей
  6. Создание API для валидации JWT
  7. Создание API для учетных записей пользователей
  8. Создание интерфейса для регистрации пользователей
  9. Создание интерфейса для входа пользователей
  10. Создание интерфейса домашней страницы
  11. Создание интерфейса для страницы аккаунта пользователя

1. Что такое JWT

JWT (JSON Web Token) - это формат упаковки данных, который позволяет обеспечить безопасную передачу информации между клиентом и сервером в JSON-формате.

Токены будут создаваться на сервере, подписываться секретным ключом с последующей передачей клиенту для подтверждения своей личности.

Информация будет надёжно защищена, т.к. она будет иметь цифровую подпись.

Пример: сервер генерирует токен "пользователь вошёл как администратор" и предоставляет его клиенту. Затем клиент использует этот токен для доказательства того, он он вошёл "как администратор".

2. Файловая структура

  • authentication-jwt/
    • api/
      • config/
        • core.php
        • database.php
      • libs/
        • php-jwt-master/
      • objects/
        • user.php
      • create_user.php
      • login.php
      • update_user.php
      • validate_token.php
    • { } custom.css
    • HTML5index.html

3. Настройка базы данных

Создадим базу данных api_db, а в ней таблицу users.

Таблица следующего вида:

Таблица базы данных users
-- phpMyAdmin SQL Dump


SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET AUTOCOMMIT = 0;
START TRANSACTION;
SET time_zone = "+00:00";

--

-- База данных: `api_db`

--


-- --------------------------------------------------------


--

-- Структура таблицы `users`

--


CREATE TABLE `users` (
  `id` int(11) NOT NULL,
  `firstname` varchar(256) NOT NULL,
  `lastname` varchar(256) NOT NULL,
  `email` varchar(256) NOT NULL,
  `password` varchar(2048) NOT NULL,
  `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

--

-- Индексы сохранённых таблиц

--


--

-- Индексы таблицы `users`

--

ALTER TABLE `users`
  ADD PRIMARY KEY (`id`);

--

-- AUTO_INCREMENT для сохранённых таблиц

--


--

-- AUTO_INCREMENT для таблицы `users`

--

ALTER TABLE `users`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT;COMMIT;

Создадим папку для проекта authentication-jwt

Я буду использовать OpenServer, поэтому папку проекта я создам в следующей директории:

D:\OSPanel\domains\authentication-jwt\

Будем считать, что у вас уже структура подготовлена (смотрите п.2).

Откроем файл database.php в папке api/config/ - файл для соединения с базой данных

Добавим в него следующий код:

<?php
// используем для подключения к базе данных MySQL

class Database {
 
    // учетные данные базы данных

    private $host = "localhost";
    private $db_name = "api_db";
    private $username = "root";
    private $password = "";
    public $conn;
 
    // получаем соединение с базой данных

    public function getConnection() {
 
        $this->conn = null;
 
        try {
            $this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->db_name, $this->username, $this->password);
        } catch(PDOException $exception) {
            echo "Connection error: " . $exception->getMessage();
        }
 
        return $this->conn;
    }
}
?>

4. Создание API для регистрации пользователей

Нам нужно установить заголовки, чтобы файл для создания пользователей принимал только данные JSON

В папке api в файл create_user.php добавим следующий код

<?php
// требуемые заголовки

header("Access-Control-Allow-Origin: http://authentication-jwt/");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
 
// подключение к БД

// файлы, необходимые для подключения к базе данных

include_once 'config/database.php';
include_once 'objects/user.php';
 
// получаем соединение с базой данных

$database = new Database();
$db = $database->getConnection();
 
// создание объекта 'User'

$user = new User($db);
 
// отправляемые данные будут здесь

Информация о пользователе будет отправлена через HTML-форму и JavaScript код. Мы увидим это позже. Нам необходимо назначить отправляемые данные в свойствах объекта, такие как имя, фамилия и т.п.

Замените комментарий // отправляемые данные будут здесь в файле create_user.php следующим кодом:

// получаем данные

$data = json_decode(file_get_contents("php://input"));
 
// устанавливаем значения

$user->firstname = $data->firstname;
$user->lastname = $data->lastname;
$user->email = $data->email;
$user->password = $data->password;
 
// здесь будет метод create()

Мы будем использовать метод create(), который сообщит нам о том, был создан пользователь или нет.

Замените комментарий // здесь будет метод create() в файле create_user.php следующим кодом:

// создание пользователя

if (
    !empty($user->firstname) &&
    !empty($user->email) &&
    !empty($user->password) &&
    $user->create()
) {
    // устанавливаем код ответа

    http_response_code(200);
 
    // покажем сообщение о том, что пользователь был создан

    echo json_encode(array("message" => "Пользователь был создан."));
}
 
// сообщение, если не удаётся создать пользователя

else {
 
    // устанавливаем код ответа

    http_response_code(400);
 
    // покажем сообщение о том, что создать пользователя не удалось

    echo json_encode(array("message" => "Невозможно создать пользователя."));
}
?>

Создание объекта класса User

Предыдущий файл не будет работать без объекта класса user

Откройте api/objects/user.php и внесите следующий код:

<?php
// объект 'user'

class User {
 
    // подключение к БД таблице "users"

    private $conn;
    private $table_name = "users";
 
    // свойства объекта

    public $id;
    public $firstname;
    public $lastname;
    public $email;
    public $password;
 
    // конструктор класса User

    public function __construct($db) {
        $this->conn = $db;
    }

    // Создание нового пользователя

    function create() {
    
        // Вставляем запрос

        $query = "INSERT INTO " . $this->table_name . "
                SET
                    firstname = :firstname,
                    lastname = :lastname,
                    email = :email,
                    password = :password";
    
        // подготовка запроса

        $stmt = $this->conn->prepare($query);
    
        // инъекция

        $this->firstname=htmlspecialchars(strip_tags($this->firstname));
        $this->lastname=htmlspecialchars(strip_tags($this->lastname));
        $this->email=htmlspecialchars(strip_tags($this->email));
        $this->password=htmlspecialchars(strip_tags($this->password));
    
        // привязываем значения

        $stmt->bindParam(':firstname', $this->firstname);
        $stmt->bindParam(':lastname', $this->lastname);
        $stmt->bindParam(':email', $this->email);
    
        // для защиты пароля

        // хешируем пароль перед сохранением в базу данных

        $password_hash = password_hash($this->password, PASSWORD_BCRYPT);
        $stmt->bindParam(':password', $password_hash);
    
        // Выполняем запрос

        // Если выполнение успешно, то информация о пользователе будет сохранена в базе данных

        if($stmt->execute()) {
            return true;
        }
    
        return false;
    }

    // здесь будет метод emailExists()

}

Тестирование API

Нам нужно использовать POSTMAN для тестирования нашего API. Скачать его можно здесь

Сначала мы проверим успешность создания пользователя. Запустим POSTMAN.

Введём следующий URL запрос

http://authentication-jwt/api/create_user.php

Нажмите Body, затем raw и вставьте следующее значение JSON

{
  "firstname" : "Vasiliy",
  "lastname" : "Ivanov",
  "email" : "vasya@coder.com",
  "password" : "888"
}

Нажмите кнопку Send. Если сделали верно, должны увидеть следующее:

POSTMAN - тест создания пользователя

Чтобы проверить ошибку создания пользователя, просто удалите значение пароля и нажмите кнопку "Send"

POSTMAN - невозможно создать пользователя

5. Создание API для входа пользователей

В приведенном ниже коде установим заголовки, чтобы файл знал откуда должен поступить запрос и какой тип данных принимается

Откроем файл api/login.php и поместим в него следующий код

<?php
// заголовки

header("Access-Control-Allow-Origin: http://authentication-jwt/");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
 
// здесь будет соединение с БД

Мы сравним электронную почту пользователя и пароль из базы данных, поэтому нам нужно подключение к БД.

Нам также нужно создать экземпляр пользовательской таблицы, это позволит нам проверить, существует ли электронная почта, и прочитать хешированный пароль.

Замените комментарий // здесь будет соединение с БД в файле login.php следующим кодом:

// файлы необходимые для соединения с БД

include_once 'config/database.php';
include_once 'objects/user.php';
 
// получаем соединение с базой данных 

$database = new Database();
$db = $database->getConnection();
 
// создание объекта 'User'

$user = new User($db);
 
// получаем данные 

$data = json_decode(file_get_contents("php://input"));
 
// устанавливаем значения 

$user->email = $data->email;
$email_exists = $user->emailExists();
 
// файлы для JWT будут здесь

Проверка на существование e-mail

Добавим метод emailExists() в наш класс объектов User

Этот метод вернёт истину (true), если отправленный e-mail существует, иначе вернёт ложь (false)

Замените комментарий // здесь будет метод emailExists() в файле /api/objects/user.php следующим кодом

// Проверка, существует ли электронная почта в нашей базе данных

function emailExists(){
 
    // запрос, чтобы проверить, существует ли электронная почта

    $query = "SELECT id, firstname, lastname, password
            FROM " . $this->table_name . "
            WHERE email = ?
            LIMIT 0,1";
 
    // подготовка запроса 

    $stmt = $this->conn->prepare( $query );
 
    // инъекция

    $this->email=htmlspecialchars(strip_tags($this->email));
 
    // привязываем значение e-mail

    $stmt->bindParam(1, $this->email);
 
    // выполняем запрос

    $stmt->execute();
 
    // получаем количество строк

    $num = $stmt->rowCount();
 
    // если электронная почта существует,

    // присвоим значения свойствам объекта для легкого доступа и использования для php сессий

    if($num>0) {
 
        // получаем значения

        $row = $stmt->fetch(PDO::FETCH_ASSOC);
 
        // присвоим значения свойствам объекта

        $this->id = $row['id'];
        $this->firstname = $row['firstname'];
        $this->lastname = $row['lastname'];
        $this->password = $row['password'];
 
        // вернём 'true', потому что в базе данных существует электронная почта

        return true;
    }
 
    // вернём 'false', если адрес электронной почты не существует в базе данных

    return false;
}
 
// здесь будет метод update()

Создание JWT (JSON web token)

Заменим комментарий // файлы для JWT будут здесь в файле api/login.php на следующий код

// подключение файлов jwt

include_once 'config/core.php';
include_once 'libs/php-jwt-master/src/BeforeValidException.php';
include_once 'libs/php-jwt-master/src/ExpiredException.php';
include_once 'libs/php-jwt-master/src/SignatureInvalidException.php';
include_once 'libs/php-jwt-master/src/JWT.php';
use \Firebase\JWT\JWT;
 
// существует ли электронная почта и соответствует ли пароль тому, что находится в базе данных

if ( $email_exists && password_verify($data->password, $user->password) ) {
 
    $token = array(
       "iss" => $iss,
       "aud" => $aud,
       "iat" => $iat,
       "nbf" => $nbf,
       "data" => array(
           "id" => $user->id,
           "firstname" => $user->firstname,
           "lastname" => $user->lastname,
           "email" => $user->email
       )
    );
 
    // код ответа

    http_response_code(200);
 
    // создание jwt

    $jwt = JWT::encode($token, $key);
    echo json_encode(
        array(
            "message" => "Успешный вход в систему.",
            "jwt" => $jwt
        )
    );
 
}
 
// Если электронная почта не существует или пароль не совпадает,

// сообщим пользователю, что он не может войти в систему

else {
 
  // код ответа

  http_response_code(401);

  // сказать пользователю что войти не удалось

  echo json_encode(array("message" => "Ошибка входа."));
}
?>

Создание файла конфигурации (ядра)

Файл login.php не будет работать без файла core.php. Этот файл содержит общие настройки / переменные нашего приложения.

У нас есть переменные, используемые нашей библиотекой JWT для кодирования и декодирования токена. Значение $key должно быть вашим собственным и уникальным секретным ключом.

iss - адрес или имя удостоверяющего центра

aud - имя клиента для которого токен выпущен

iat - время, когда был выпущен JWT

nbf - время, начиная с которого может быть использован (не раньше, чем)

Вы также можете использовать exp - идентифицирует время истечения срока действия токена

Откроем api/config/core.php и добавим следующий код

<?php
// показывать сообщения об ошибках

error_reporting(E_ALL);
 
// установить часовой пояс по умолчанию

date_default_timezone_set('Europe/Moscow');
 
// переменные, используемые для JWT

$key = "your_secret_key";
$iss = "http://any-site.org";
$aud = "http://any-site.com";
$iat = 1356999524;
$nbf = 1357000000;
?>

Скачайте библиотеку PHP-JWT c GitHub'а

Скопируйте содержимое библиотеки в api/libs/

Тест входа в систему

Введём следующий URL запрос

http://authentication-jwt/api/login.php

В Body вставьте следующее значение JSON

{
  "email" : "vasya@coder.com",
  "password" : "888"
}

Нам нужно сохранить сгенерированный JWT чтобы потом его использовать для проверки

POSTMAN - вход пользователя

Для проверки на неудачный вход в систему измените значение пароля на 222 (это неверный пароль)

POSTMAN - ошибка входа пользователя

6. Создание API для валидации JWT

Приступим к наполнению файла api/validate_token.php

Установим правильные заголовки. Этот файл вернет вывод в формате JSON и примет запросы от указанного URL

<?php
// заголовки

header("Access-Control-Allow-Origin: http://localhost/rest-api-authentication-example/");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
 
// требуется для декодирования JWT

include_once 'config/core.php';
include_once 'libs/php-jwt-master/src/BeforeValidException.php';
include_once 'libs/php-jwt-master/src/ExpiredException.php';
include_once 'libs/php-jwt-master/src/SignatureInvalidException.php';
include_once 'libs/php-jwt-master/src/JWT.php';
use \Firebase\JWT\JWT;
 
// получаем значение веб-токена JSON

$data = json_decode(file_get_contents("php://input"));

// получаем JWT

$jwt=isset($data->jwt) ? $data->jwt : "";

// если JWT не пуст

if($jwt) {
 
    // если декодирование выполнено успешно, показать данные пользователя

    try {
        // декодирование jwt

        $decoded = JWT::decode($jwt, $key, array('HS256'));
 
        // код ответа

        http_response_code(200);
 
        // показать детали

        echo json_encode(array(
            "message" => "Доступ разрешен.",
            "data" => $decoded->data
        ));
 
    }
 
    // если декодирование не удалось, это означает, что JWT является недействительным

    catch (Exception $e){
    
        // код ответа

        http_response_code(401);
    
        // сообщить пользователю отказано в доступе и показать сообщение об ошибке

        echo json_encode(array(
            "message" => "Доступ закрыт.",
            "error" => $e->getMessage()
        ));
    }
}
 
// показать сообщение об ошибке, если jwt пуст

else{
 
    // код овтета

    http_response_code(401);
 
    // сообщить пользователю что доступ запрещен

    echo json_encode(array("message" => "Доступ запрещён."));
}
?>

Тест на успешный доступ

Введём следующий URL

http://authentication-jwt/api/validate_token.php

Введите JSON токен, который мы получили ранее. Приведенный ниже токен JSON отличается от вашего.

{
  "jwt" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUuY29tIiwiaWF0IjoxMzU2OTk5NTI0LCJuYmYiOjEzNTcwMDAwMDAsImRhdGEiOnsiaWQiOiIyIiwiZmlyc3RuYW1lIjoiVmFzaWxpeSIsImxhc3RuYW1lIjoiSXZhbm92IiwiZW1haWwiOiJ2YXN5YUBjb2Rlci5jb20ifX0.W4ghyd6D4jRAnOeiT4-wTjdjaGh9EYmJDlssrai6A80"
}

Так должно выглядеть в POSTMAN

Валидация токена

Чтобы проверить наличие неудачного доступа, просто добавьте слово «EDITED» в свой JWT. Это сделает JWT неправильным и приведет к отказу в доступе. Это должно выглядеть так.

POSTMAN - ошибка входа пользователя

7. Создание API для учетных записей пользователей

Откроем api/update_user.php и вставим следующий код

<?php
// required headers

header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
 
// требуется для кодирования веб-токена JSON

include_once 'config/core.php';
include_once 'libs/php-jwt-master/src/BeforeValidException.php';
include_once 'libs/php-jwt-master/src/ExpiredException.php';
include_once 'libs/php-jwt-master/src/SignatureInvalidException.php';
include_once 'libs/php-jwt-master/src/JWT.php';
use \Firebase\JWT\JWT;
 
// файлы, необходимые для подключения к базе данных 

include_once 'config/database.php';
include_once 'objects/user.php';
 
// получаем соединение с базой данных 

$database = new Database();
$db = $database->getConnection();
 
// создание объекта 'User' 

$user = new User($db);
 
// получаем данные 

$data = json_decode(file_get_contents("php://input"));
 
// получаем jwt

$jwt=isset($data->jwt) ? $data->jwt : "";
 
// если JWT не пуст

if($jwt) {
 
    // если декодирование выполнено успешно, показать данные пользователя

    try {
 
        // декодирование jwt

        $decoded = JWT::decode($jwt, $key, array('HS256'));
 
        // Нам нужно установить отправленные данные (через форму HTML) в свойствах объекта пользователя

        $user->firstname = $data->firstname;
        $user->lastname = $data->lastname;
        $user->email = $data->email;
        $user->password = $data->password;
        $user->id = $decoded->data->id;
        
        // создание пользователя

        if($user->update()) {
            // сгенерировать заново JWT здесь

        }
        
        // сообщение, если не удается обновить пользователя

        else {
            // код ответа

            http_response_code(401);
        
            // показать сообщение об ошибке

            echo json_encode(array("message" => "Невозможно обновить пользователя."));
        }
    }
 
    // если декодирование не удалось, это означает, что JWT является недействительным

    catch (Exception $e){
    
        // код ответа

        http_response_code(401);
    
        // сообщение об ошибке

        echo json_encode(array(
            "message" => "Доступ закрыт",
            "error" => $e->getMessage()
        ));
    }
}

// показать сообщение об ошибке, если jwt пуст

else {
 
    // код ответа

    http_response_code(401);
 
    // сообщить пользователю что доступ запрещен

    echo json_encode(array("message" => "Доступ закрыт."));
}
?>

Создание метода Update()

Выполним запрос UPDATE, очистку данных и привязку

Замените комментарий // здесь будет метод update() в файле /api/objects/user.php следующим кодом

// обновить запись пользователя

public function update(){
 
    // Если в HTML-форме был введен пароль (необходимо обновить пароль)

    $password_set=!empty($this->password) ? ", password = :password" : "";
 
    // если не введен пароль - не обновлять пароль

    $query = "UPDATE " . $this->table_name . "
            SET
                firstname = :firstname,
                lastname = :lastname,
                email = :email
                {$password_set}
            WHERE id = :id";
 
    // подготовка запроса 

    $stmt = $this->conn->prepare($query);
 
    // инъекция (очистка)

    $this->firstname=htmlspecialchars(strip_tags($this->firstname));
    $this->lastname=htmlspecialchars(strip_tags($this->lastname));
    $this->email=htmlspecialchars(strip_tags($this->email));
 
    // привязываем значения с HTML формы

    $stmt->bindParam(':firstname', $this->firstname);
    $stmt->bindParam(':lastname', $this->lastname);
    $stmt->bindParam(':email', $this->email);
 
    // метод password_hash () для защиты пароля пользователя в базе данных

    if(!empty($this->password)){
        $this->password=htmlspecialchars(strip_tags($this->password));
        $password_hash = password_hash($this->password, PASSWORD_BCRYPT);
        $stmt->bindParam(':password', $password_hash);
    }
 
    // уникальный идентификатор записи для редактирования

    $stmt->bindParam(':id', $this->id);
 
    // Если выполнение успешно, то информация о пользователе будет сохранена в базе данных 

    if($stmt->execute()) {
        return true;
    }
 
    return false;
}

Повторная генерация JWT

Замените комментарий // сгенерировать заново JWT здесь в файле /api/update_user.php следующим кодом

// нам нужно заново сгенерировать JWT, потому что данные пользователя могут отличаться

$token = array(
   "iss" => $iss,
   "aud" => $aud,
   "iat" => $iat,
   "nbf" => $nbf,
   "data" => array(
       "id" => $user->id,
       "firstname" => $user->firstname,
       "lastname" => $user->lastname,
       "email" => $user->email
   )
);
$jwt = JWT::encode($token, $key);
 
// код ответа

http_response_code(200);
 
// ответ в формате JSON

echo json_encode(
    array(
        "message" => "Пользователь был обновлён",
        "jwt" => $jwt
    )
);

Тест успешного обновления пользователя

Введём следующий URL в POSTMAN

http://authentication-jwt/api/update_user.php

В разделе Body изменим информацию о текущем пользователе с помощью веб-токена JSON, который мы получили ранее (и сохранили).

{
  "firstname" : "Vasiliy",
  "lastname" : "Ivanov",
  "email" : "vasya2@coder.com",
  "password" : "888",
  "jwt" : "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOlwvXC9leGFtcGxlLm9yZyIsImF1ZCI6Imh0dHA6XC9cL2V4YW1wbGUuY29tIiwiaWF0IjoxMzU2OTk5NTI0LCJuYmYiOjEzNTcwMDAwMDAsImRhdGEiOnsiaWQiOiIyIiwiZmlyc3RuYW1lIjoiVmFzaWxpeSIsImxhc3RuYW1lIjoiSXZhbm92IiwiZW1haWwiOiJ2YXN5YUBjb2Rlci5jb20ifX0.W4ghyd6D4jRAnOeiT4-wTjdjaGh9EYmJDlssrai6A80"
}

Должно выглядеть примерно так

Успешное обновление информации о пользователе

При обновлении информации о пользователе происходит генерация нового токена JWT

Чтобы проверить, не удалось ли обновить пользователя, вы можете просто добавить слово EDITED в правленную JWT, или просто удалить JWT. Это должно выглядеть следующим образом.

Ошибка обновления информации о пользователе

8. Создание интерфейса для регистрации пользователей

Мы будем использовать API, которые мы создали ранее. Все необходимые коды будут в одном файле index.html с использованием HTML, CSS и JavaScript.

Откройте файл index.html в нашей папке authentication-jwt. Поместите следующий код

<!doctype html>
<html lang="ru">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
 
        <title>Rest API Authentication Example</title>

        <!-- Bootstrap 4 CSS and custom CSS -->
        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous" />
        <link rel="stylesheet" href="custom.css" />
 
    </head>
<body>
 
<!-- navbar -->
<nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top">
  <a class="navbar-brand" href="#">Navbar</a>
  <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
      <div class="navbar-nav">
          <a class="nav-item nav-link" href="#" id='home'>Домашняя страница</a>
          <a class="nav-item nav-link" href="#" id='update_account'>Учетная запись</a>
          <a class="nav-item nav-link" href="#" id='logout'>Выход</a>
          <a class="nav-item nav-link" href="#" id='login'>Вход</a>
          <a class="nav-item nav-link" href="#" id='sign_up'>Регистрация</a>
      </div>
  </div>
</nav>
<!-- /navbar -->

<!-- container -->
<main role="main" class="container starter-template">
 
  <div class="row">
      <div class="col">

          <!-- здесь будут подсказки / быстрые сообщения -->
          <div id="response"></div>

          <!-- здесь появится основной контент -->
          <div id="content"></div>
      </div>
  </div>

</main>
<!-- /container -->
 
<!-- jQuery & Bootstrap 4 JavaScript libraries -->
<script src="http://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

<!-- здесь будет jQuery код -->

</body>
</html>

Создадим файл custom.css который мы подключили в шапке, со следующим содержимым

body { padding-top: 45px; }
.starter-template { padding: 35px 22px; }
#logout{ display:none; }

Показать HTML форму регистрации

Когда вы нажмёте на меню "Регистрация" на навигационной панели, отобразится форма регистрации

Замените комментарий здесь будет jQuery код следующим кодом

<script>
// jQuery код

jQuery(function($) {

    // показать форму регистрации

    $(document).on('click', '#sign_up', function(){

        var html = `
            <h2>Регистрация</h2>
            <form id='sign_up_form'>
                <div class="form-group">
                    <label for="firstname">Имя</label>
                    <input type="text" class="form-control" name="firstname" id="firstname" required />
                </div>

                <div class="form-group">
                    <label for="lastname">Фамилия</label>
                    <input type="text" class="form-control" name="lastname" id="lastname" required />
                </div>

                <div class="form-group">
                    <label for="email">Email</label>
                    <input type="email" class="form-control" name="email" id="email" required />
                </div>

                <div class="form-group">
                    <label for="password">Пароль</label>
                    <input type="password" class="form-control" name="password" id="password" required />
                </div>

                <button type='submit' class='btn btn-primary'>Зарегистрироваться</button>
            </form>
        `;

        clearResponse();
        $('#content').html(html);
    });

    // выполнение кода при отправке формы


    // показать форму входа при клике на кнопку


    // Удаление всех быстрых сообщений

    function clearResponse(){
        $('#response').html('');
    }

    // функция showLoginPage()

    
    // serializeObject будет здесь

});
</script>

Нам нужно обработать данные формы, когда она будет отправлена.

Замените комментарий // выполнение кода при отправке формы следующим кодом

// выполнение кода при отправке формы

$(document).on('submit', '#sign_up_form', function(){

    // получаем данные формы

    var sign_up_form=$(this);
    var form_data=JSON.stringify(sign_up_form.serializeObject());

    // отправить данные формы в API

    $.ajax({
        url: "api/create_user.php",
        type : "POST",
        contentType : 'application/json',
        data : form_data,
        success : function(result) {
            // в случае удачного завершения запроса к серверу, 

            // сообщим пользователю, что он успешно зарегистрировался и очистим поля ввода

            $('#response').html("<div class='alert alert-success'>Регистрация зарешена успешно. Пожалуйста, войдите.</div>");
            sign_up_form.find('input').val('');
        },
        error: function(xhr, resp, text){
            // при ошибке сообщить пользователю, что регистрация не удалась

            $('#response').html("<div class='alert alert-danger'>Невозможно зарегистрироваться. Пожалуйста, свяжитесь с администратором.</div>");
        }
    });

    return false;
});

9. Создание интерфейса для входа пользователей

Если щёлкнуть на меню «Вход» на панели навигации, отобразится форма входа.

Замените комментарий // показать форму входа при клике на кнопку следующим кодом

// показать форму входа

$(document).on('click', '#login', function(){
    showLoginPage();
});

// при отправке формы входа

$(document).on('submit', '#login_form', function(){

    // получаем данные формы

    var login_form=$(this);
    var form_data=JSON.stringify(login_form.serializeObject());

    // отправить данные формы в API

    $.ajax({
        url: "api/login.php",
        type : "POST",
        contentType : 'application/json',
        data : form_data,
        success : function(result){

            // сохранить JWT в куки

            setCookie("jwt", result.jwt, 1);

            // показать домашнюю страницу и сообщить пользователю, что вход был успешным

            showHomePage();
            $('#response').html("<div class='alert alert-success'>Успешный вход в систему.</div>");

        },
        error: function(xhr, resp, text){
            // при ошибке сообщим пользователю, что вход в систему не выполнен и очистим поля ввода

            $('#response').html("<div class='alert alert-danger'>Ошибка входа. Email или пароль указан неверно.</div>");
            login_form.find('input').val('');
        }
    });

    return false;
});

// показ домашней страницы

Замените комментарий // функция showLoginPage() следующим кодом

// функция показывает HTML-форму для входа в систему.

function showLoginPage(){

    // удаление jwt

    setCookie("jwt", "", 1);

    // форма входа

    var html = `
        <h2>Вход</h2>
        <form id='login_form'>
            <div class='form-group'>
                <label for='email'>Email адрес</label>
                <input type='email' class='form-control' id='email' name='email' placeholder='Введите email'>
            </div>

            <div class='form-group'>
                <label for='password'>Пароль</label>
                <input type='password' class='form-control' id='password' name='password' placeholder='Введите пароль'>
            </div>
 
            <button type='submit' class='btn btn-primary'>Войти</button>
        </form>
        `;

    $('#content').html(html);
    clearResponse();
    showLoggedOutMenu();
}

// функция setCookie() поможет нам сохранить JWT в файле cookie

function setCookie(cname, cvalue, exdays) {
    var d = new Date();
    d.setTime(d.getTime() + (exdays*24*60*60*1000));
    var expires = "expires="+ d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}

// эта функция сделает меню похожим на опции для пользователя, вышедшего из системы.

function showLoggedOutMenu(){
    // показать кнопку входа и регистрации в меню навигации

    $("#login, #sign_up").show();
    $("#logout").hide(); // скрыть кнопку выхода

}

// здесь будет функция showHomePage()

Замените комментарий // serializeObject будет здесь следующим кодом

// функция для преобразования значений формы в формат JSON

$.fn.serializeObject = function(){

    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

10. Создание интерфейса домашней страницы

Замените комментарий // показ домашней страницы следующим кодом

// показать домашнюю страницу

$(document).on('click', '#home', function(){
    showHomePage();
    clearResponse();
});

// показать форму обновления аккаунта

Замените комментарий // здесь будет функция showHomePage() следующим кодом

// функция показать домашнюю страницу

function showHomePage(){

    // валидация JWT для проверки доступа

    var jwt = getCookie('jwt');
    $.post("api/validate_token.php", JSON.stringify({ jwt:jwt })).done(function(result) {

        // если прошел валидацию, показать домашнюю страницу

        var html = `
            <div class="card">
                <div class="card-header">Добро пожаловать!</div>
                <div class="card-body">
                    <h5 class="card-title">Вы вошли в систему.</h5>
                    <p class="card-text">Вы не сможете получить доступ к домашней странице и страницам учетной записи, если вы не вошли в систему.</p>
                </div>
            </div>
        `;

        $('#content').html(html);
        showLoggedInMenu();
    })

    // показать страницу входа при ошибке

    .fail(function(result){
        showLoginPage();
        $('#response').html("<div class='alert alert-danger'>Пожалуйста войдите, чтобы получить доступ к домашней станице</div>");
    });
}
 
// Функция поможет нам прочитать JWT, который мы сохранили ранее.

function getCookie(cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for(var i = 0; i <ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' '){
            c = c.substring(1);
        }

        if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

// если пользователь залогинен

function showLoggedInMenu(){
    // скрыть кнопки вход и зарегистрироваться с панели навигации и показать кнопку выхода

    $("#login, #sign_up").hide();
    $("#logout").show();
}

// здесь будет функция showUpdateAccountForm()

11. Создание интерфейса для страницы аккаунта пользователя

Замените комментарий // показать форму обновления аккаунта следующим кодом

$(document).on('click', '#update_account', function(){
    showUpdateAccountForm();
});

// срабатывание при отправке формы «обновить аккаунт»

$(document).on('submit', '#update_account_form', function(){

    // дескриптор для update_account_form

    var update_account_form=$(this);

    // валидация JWT для проверки доступа

    var jwt = getCookie('jwt');

    // получаем данные формы

    var update_account_form_obj = update_account_form.serializeObject()

    // добавим JWT

    update_account_form_obj.jwt = jwt;

    // преобразуем значения формы в JSON с помощью функции stringify ()

    var form_data=JSON.stringify(update_account_form_obj);

    // отправить данные формы в API

    $.ajax({
        url: "api/update_user.php",
        type : "POST",
        contentType : 'application/json',
        data : form_data,
        success : function(result) {

            // сказать, что учетная запись пользователя была обновлена

            $('#response').html("<div class='alert alert-success'>Учетная запись обновлена.</div>");

            // сохраняем новый JWT в cookie

            setCookie("jwt", result.jwt, 1);
        },

        // показать сообщение об ошибке пользователю

        error: function(xhr, resp, text){
            if(xhr.responseJSON.message=="Невозможно обновить пользователя."){
                $('#response').html("<div class='alert alert-danger'>Невозможно обновить пользователя.</div>");
            }

            else if(xhr.responseJSON.message=="Доступ закрыт."){
                showLoginPage();
                $('#response').html("<div class='alert alert-success'>Доступ закрыт. Пожалуйста войдите</div>");
            }
        }
    });

    return false;
});

// выйти из системы

$(document).on('click', '#logout', function(){
    showLoginPage();
    $('#response').html("<div class='alert alert-info'>Вы вышли из системы.</div>");
});

Замените комментарий // здесь будет функция showUpdateAccountForm() следующим кодом

function showUpdateAccountForm(){
  // валидация JWT для проверки доступа

  var jwt = getCookie('jwt');
  $.post("api/validate_token.php", JSON.stringify({ jwt:jwt })).done(function(result) {

    // если валидация прошла успешно, покажем данные пользователя в форме

    var html = `
            <h2>Обновление аккаунта</h2>
            <form id='update_account_form'>
                <div class="form-group">
                    <label for="firstname">Имя</label>
                    <input type="text" class="form-control" name="firstname" id="firstname" required value="` + result.data.firstname + `" />
                </div>

                <div class="form-group">
                    <label for="lastname">Фамилия</label>
                    <input type="text" class="form-control" name="lastname" id="lastname" required value="` + result.data.lastname + `" />
                </div>

                <div class="form-group">
                    <label for="email">Email</label>
                    <input type="email" class="form-control" name="email" id="email" required value="` + result.data.email + `" />
                </div>

                <div class="form-group">
                    <label for="password">Пароль</label>
                    <input type="password" class="form-control" name="password" id="password" />
                </div>

                <button type='submit' class='btn btn-primary'>
                    Сохранить
                </button>
            </form>
        `;

    clearResponse();
    $('#content').html(html);
  })

  // в случае ошибки / сбоя сообщите пользователю, что ему необходимо войти в систему, чтобы увидеть страницу учетной записи.

  .fail(function(result){
      showLoginPage();
      $('#response').html("<div class='alert alert-danger'>Пожалуйста, войдите, чтобы получить доступ к странице учетной записи.</div>");
  });
}

Оригинал статьи

16/09/2019 16:08