Welcome

Простая аутентификация на PHP

Многие новички до сих пор попадают в тупик при написании простейшей аутентификации в PHP. На Тостере с завидной регулярностью попадаются вопросы о том, как сравнить сохраненный пароль с паролем полученным из формы логина. Здесь будет краткая статья-туториал на эту тему.

Disclaimer: статья рассчитана на совершенных новичков. Умудрённые опытом разработчики ничего нового здесь не найдут, но могут указать на возможные недочёты =).

Для написания системы аутентификации будем использовать базу данных MySQL/MariaDB, PHP, PDO, функции для работы с паролями, для построения интерфейса возьмём bootstrap.

Для начала создадим базу. Пусть она называется php-auth-demo. В новой базе создадим таблицу пользователей users :

CREATE TABLE `users` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `username` varchar(255) COLLATE utf8mb4_general_ci NOT NULL, `password` varchar(255) COLLATE utf8mb4_general_ci NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

Создадим конфиг с данными для подключения к базе.

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

 'php-auth-demo', 'db_host' => '127.0.0.1', 'db_user' => 'mysql', 'db_pass' => 'mysql', ];

И сделаем «загрузочный» файл, который будем подключать вначале всех остальных файлов.

В реальных проектах обычно используется автозагрузка необходимых файлов. Но этот момент выходит за рамки статьи, и в демо-примере мы обойдёмся простым подключением.

В «загрузочном» файле мы будем инициализировать сессию и объявим некоторые функции-помощники.

setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); > return $pdo; >

Функция pdo() даст нам доступ к объекту PDO в любом месте нашего кода.

Далее нам нужна форма регистрации. Разместим её прямо в файле index.php .

 

Здесь всё просто: два поля, кнопка и форма, отправляющая запрос на файл do_register.php методом POST. Процесс регистрации пользователя опишем в файле do_register.php .

prepare("SELECT * FROM `users` WHERE `username` = :username"); $stmt->execute(['username' => $_POST['username']]); if ($stmt->rowCount() > 0) < flash('Это имя пользователя уже занято.'); header('Location: /'); // Возврат на форму регистрации die; // Остановка выполнения скрипта >// Добавим пользователя в базу $stmt = pdo()->prepare("INSERT INTO `users` (`username`, `password`) VALUES (:username, :password)"); $stmt->execute([ 'username' => $_POST['username'], 'password' => password_hash($_POST['password'], PASSWORD_DEFAULT), ]); header('Location: login.php');

В самом начале подключим наш «загрузчик».

Потом проверим, не занято ли имя пользователя. Для этого сделаем выборку из таблицы указав в условии полученное из формы имя пользователя. Обратите внимание, для запросов здесь и далее мы будем использовать подготовленные запросы, что обезопасит нас от SQL-инъекций. Для этого в тексте SQL-запроса мы указываем специальные плейсхолдеры, а при выполнении ассоциируем с ними ненадёжные данные (ненадёжными данными следует считать всё, что приходит из вне – $_GET, $_POST, $_REQUEST, $_COOKIE). После выполнения запроса мы просто проверим количество возвращённых строк. Если их больше нуля, то имя пользователя уже занято. В этом случае мы выведем сообщение и вернём пользователя на форму регистрации.

Читайте также:  Вычислить сумму чисел массива java

Я написал «больше нуля», но по факту, из-за того, что поле username в таблице уникальное, rowCount() может нам вернуть лишь два возможных значения: 0 и 1 .

В приведённом выше коде мы использовали функцию flash() . Данная функция предназначена для «одноразовых» сообщений. Если вызвать её со строковым параметром, то она сохранит эту строку в сессии, а если вызвать без параметров, то выведет из сессии сохранённое сообщение и затем удалит его в сессии. Добавим эту функцию в файл boot.php .

function flash(?string $message = null) < if ($message) < $_SESSION['flash'] = $message; >else < if (!empty($_SESSION['flash'])) < ?>  unset($_SESSION['flash']); > >

А также вызовем её нa форме регистрации, для вывода возможных сообщений.

На данном этапе простейший функционал регистрации нового пользователя готов.

Если мы посмотрим код регистрации выше, то увидим, что в случае успешной регистрации, мы перенаправляем пользователя на страницу логина. Самое время ее написать.

Login

Register

В виду простоты примера, она практически повторяет форму регистрации. Интереснее будет посмотреть на сам процесс логина в файле do_login.php .

prepare("SELECT * FROM `users` WHERE `username` = :username"); $stmt->execute(['username' => $_POST['username']]); if (!$stmt->rowCount()) < flash('Пользователь с такими данными не зарегистрирован'); header('Location: login.php'); die; >$user = $stmt->fetch(PDO::FETCH_ASSOC); // проверяем пароль if (password_verify($_POST['password'], $user['password'])) < // Проверяем, не нужно ли использовать более новый алгоритм // или другую алгоритмическую стоимость // Например, если вы поменяете опции хеширования if (password_needs_rehash($user['password'], PASSWORD_DEFAULT)) < $newHash = password_hash($_POST['password'], PASSWORD_DEFAULT); $stmt = pdo()->prepare('UPDATE `users` SET `password` = :password WHERE `username` = :username'); $stmt->execute([ 'username' => $_POST['username'], 'password' => $newHash, ]); > $_SESSION['user_id'] = $user['id']; header('Location: /'); die; > flash('Пароль неверен'); header('Location: login.php');

Здесь есть важный момент. Мы не запрашиваем пользователя из таблицы по паре username/password, а используем только username. Дело в том, что даже если вы захешируете пришедший из формы логина пароль и попробуете сравнить новый хеш с сохранённым в базе, вы ничего не получите. Password_hash() использует автоматически генерируемую соль для паролей и хеши будут всегда получаться разные. Вот результат функции password_hash , вызванной несколько раз для пароля «123»:

$2y$10$loqucup11.3DL1fgDWanoettFpFJuFFd0fY6BZyiP698ZqvA4tmuy $2y$10$.LF3OzmQRtJvuZZWeWF.2u80x3ls6OEAU5J9gLHDtcYrFzJkRRPvq $2y$10$iGj/nOCavShd2vbMZTC4GOMYCqDj2YSc8qWoeqjVbD1xaKU2CgAfi

Именно поэтому необходимо использовать функцию password_verify для проверки пароля. Кроме того, данная функция использует специальный алгоритм проверки и является безопасной для атак по времени.

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

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

Для проверки того факта, что пользователь залогинен, нужно будет проверить наличие данного идентификатора в сессии. Мы для удобства напишем функцию-помощник и разместим ее в том же файле boot.php .

Теперь можем добавить проверки и изменить вывод на главной странице, если пользователь аутентифицирован.

prepare("SELECT * FROM `users` WHERE `id` = :id"); $stmt->execute(['id' => $_SESSION['user_id']]); $user = $stmt->fetch(PDO::FETCH_ASSOC); > ?> 

Welcome back, !

else < ?>

Registration

?>

А также закрыть доступ к форме логина, если пользователь уже вошёл:

Осталось добавить возможность «выйти». Форму для выхода вы можете видеть в коде выше. Сама процедура выхода простейшая, и заключается в очистке сессии.

Заключение

  • Используем PDO/MySQLi и подготовленные запросы для работы с базой данных.
  • В базе данных обязательно храним только хеш пароля.
  • Для хеширования пароля используем специальную функцию password_hash.
  • Для проверки пароля не делаем сравнение хешей, а используем специальную функцию password_verify.

Полный код примера доступен на гитхабе: ссылка на Github.

Источник

Аутентификация и авторизация через форму на PHP

Изображение баннера

Аутентификация через форму (Form-based authentication) популярна потому, что можно накрутить свою логику.

Структура

Прямо на этом сайте я создал директорию login а ней следующие файлы:

. ├── authorizer.php ├── check_credentials.php ├── index.php ├── logout.php └── welcome.php

Цель посетителя — страница welcome.php

На этой странице есть текст с приветствием и проверка — залогинился пользователь или нет

Welcome to AndreyOlegovich.ru

‘; ?>

Проверка осуществляется с помощью функции check_credentials() из файла check_credentials.php

Если переменная сессии $_SESSION[«loggedin»] не равна true пользователь отправляется на страницу с логином.

HTML форма для ввода логина и пароля будет находится в файле index.php

else < header("location: index.php"); >exit; > $username = «»; $password = «»; if (isset($_POST[‘username’]) && isset($_POST[‘password’])) < if (!empty($_POST['username']) && !empty($_POST['password'])) < $username = $_POST['username']; $password = $_POST['password']; >> echo’

HOME

Введите ваши имя пользователя и пароль

‘; ?>

Скрипт, который будет проверять введённые данные с правильными сохраните в файл authorizer.php

; echo’

menu

Welcome to eth1.ru

‘; ?>

Комментарии

Для простоты был рассмотрен вариант без применения баз данных

Я видел много инструкций где скрипт отвечающий за проверку данных находится в одном файле с HTML формой.

Также я видел вопросы на форумах в стиле «почему нужно нажимать на кнопку логин два раза»

Чтобы избавить себя от возможных проблем — скрипт и форму я держу в разных файлах.

Источник

Обработка форм сайта с помощью PHP

Обработка форм сайта с помощью PHP

Формы используют для отправки какой-либо информации на сервер, которую необходимо как-то обработать.

Места использования форм:

  1. Создание регистрации и авторизации
  2. Создание блока комментариев
  3. Создание обращения в техническую поддержку (тикеты)

Создаём форму на HTML

Код формы необходимо помещать в HTML документа.

      Здесь должна быть ваша форма. 

Я пропущу скелет документа дальше, чтобы было более понятно.

 

Введите логин:

Введите пароль:

В атрибут action нужно указать обработчик формы (PHP-скрипт). Если поле пусто, значит, обработку формы выполнил тот скрипт, в котором расположена сама форма. В атрибут method нужно указать метод отправки формы (post или get). У каждого свои плюсы и минусы. Вкратце: post отправляет данные так, что пользователь не может их увидеть, а get — так, что они видны в URL-строке браузера.

Наглядный пример getНаглядный пример post:
Наглядный пример postНемного по PHP:

При отправке формы методом POST данные записываются в суперглобальный массив $_POST.

При отправке формы методом GET данные записываются в суперглобальный массив $_GET.

К суперглобальным массивам $_POST и $_GET нужно обращаться обычным способом (как вы делаете это и с обычными ассоциативными массивами) $массив[‘ключ’].

В форме мы сделали 3 . Первые два — поле ввода логина и пароля. Третий — кнопка отправки формы.
Тег имеет атрибут type=»». Для каждого случая указывают свой тип ввода. Допустим, text устанавливают для текста, submit — для отправки формы по атрибуту (action), а password — для пароля (чтобы он отображался звёздочками *).
Кроме того, тег имеет атрибут name=»» и атрибут value=»». Value — стандартное значение элемента, name — предназначено для того, чтобы обработчик формы мог его идентифицировать.

Создаём обработчика формы

Мы перешли к самому интересному моменту статьи. Если мы обрабатываем форму на другой странице (action=»example.php»), то после нажатия кнопки подтверждения вас перекинет на указанную страницу.
Если action пуст, то страница с формой перезагрузится.
В самом верху скелета документа (перед ) открываем теги PHP и обрабатываем форму:

 // Если кнопка нажата, то выполняет тело условия if (isset($_POST['done'])) < echo 'кнопка обработчика была нажата!
'; // Если логин и пароль не пуст(есть значение), а также пароль не 123 if (!empty($_POST['login']) && $_POST['pass'] != 123 && !empty($_POST['pass'])) < echo "Всё хорошо, все поля пройдены. "; echo "Здесь должна быть ваша обработка формы. "; echo "Занесение в базу данных, отправка сообщения и т.п."; >// Если логин пуст, тогда выводит сообщение if ($_POST['login'] == '') < echo 'Логин пуст!
'; > // Если пароль популярный ||(или) пуст, тогда выводит сообщение if ($_POST['pass'] == '123' || empty($_POST['pass'])) < echo "Нельзя использовать популярные пароли. Придумайте свой!
"; > > ?>

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

В самом верху PHP-тега заводим 2 новые переменные, которые по стандарту пусты:

В проверке на пароль:

$error_pas .= "Нельзя использовать популярные пароли. Придумайте свой!
";

В проверке на логин:

.= означает то, что мы берём прошлую строку (пусто) и прибавляем к этому наше сообщение.

В форме HTML:

Добавляем после тега вставку PHP (в данном случае ), так как мы только выводим переменную. Суть проста: если ошибки в логине нет, тогда $error_login пуст, а следственно, ничего не выводится, иначе выводим там ошибку.

Введите логин:

Введите пароль:

Теперь доработаем форму, чтобы она сохраняла значения полей.

В самом начале добавляем 2 переменные:

В начало проверки на ‘нажата ли кнопка отправки’ добавляем:

$input_login = $_POST['login']; $input_pass = $_POST['pass'];

То есть мы заносим в переменные значения из суперглобального массива $_POST.

И немного изменяем нашу HTML-форму:

 

Введите логин: ">

Введите пароль: ">

Добавляем тег value, чтобы указать стандартное значение поля. Теперь если выдаётся ошибка, то значения полей сохраняются, и пользователю нужно не заново их вводить, а только исправить ошибку.

Заключение

Как видите, создать хорошую форму на PHP не так уж и сложно. Проверки, которые я показал в этой статье, не обязательно должны быть. Вы можете придумывать свои (любые) проверки на поля ввода, используя PHP. Надеюсь, что вам понравилась моя статья, и вы выучили что-то новое.

Итоговый код страницы с формой + обработчика:

Источник

Оцените статью