- Создание форм регистрации и авторизации на PHP
- Разработка форм регистрации и авторизации
- Код регистрационной формы
- Исходный код страницы авторизации
- CSS-стили для оформления форм
- Создание таблицы с учетными данными и подключение к базе данных
- Исходный код для регистрации пользователей
- Функция авторизации
- Ограничение доступа к страницам
- Типичные ошибки и способы их решения
- Некорректное имя переменной
- «Заголовки уже отправлены»
- Переменные сессии не сохраняются при переходах между страницами
- Безопасный метод авторизации на PHP
- Модель авторизации:
- Реализация
Создание форм регистрации и авторизации на PHP
Система регистрации и авторизации необходима для любого сайта, который хранит информацию о своих пользователях. Такие системы используются на сайтах самой разнообразной тематики – от образовательных платформ, которые хранят сведения о прохождении обучающих курсов и оценках, до онлайн-магазинов, которые сохраняют историю покупок и адреса пользователей. В этом руководстве мы научим вас создавать формы регистрации и авторизации с нуля.
Разработка форм регистрации и авторизации
Мы рассмотрим процесс создания простых форм для регистрации и авторизации пользователей. Регистрационная форма будет содержать поля для ввода имени, пароля и адреса электронной почты. Имя пользователя и адрес электронной почты при этом должны быть уникальными для каждого конкретного пользователя. В случае попытки регистрации второй учетной записи с таким же именем пользователя (или электронной почтой) будет выводиться сообщение об ошибке с пояснением о том, что такие данные уже используются в системе.
Код регистрационной формы
Ниже приведен HTML-код необходимый для создания формы регистрации. Сохраните его вфайле register.php.
Несмотря на простоту данной формы, для проведения простейшей валидации данных в ней используется HTML5. К примеру, использование type=»email» обеспечит уведомление пользователя о том, что он неправильно ввел адрес электронной почты. Кроме того, применение pattern позволит провести проверку имени пользователя – логин может состоять только из латинских букв и цифр.
Наиболее продвинутый способ валидации данных подразумевает использование jQuery – в этом случае разработчик получает полный контроль над показом, расположением и внешним видом сообщений об ошибках ввода. Подробнее о валидации на стороне клиента с использованием jQuery рассказывается в этой статье.
Исходный код страницы авторизации
HTML-код страницы входа в систему приведен ниже. Сохраните его в файле login.php .
CSS-стили для оформления форм
Для улучшения внешнего вида форм примените к ним следующие CSS-стили:
* < padding: 0; margin: 0; box-sizing: border-box; >body < margin: 50px auto; text-align: center; width: 800px; >h1 < font-family: 'Passion One'; font-size: 2rem; text-transform: uppercase; >label < width: 150px; display: inline-block; text-align: left; font-size: 1.5rem; font-family: 'Lato'; >input < border: 2px solid #ccc; font-size: 1.5rem; font-weight: 100; font-family: 'Lato'; padding: 10px; >form < margin: 25px auto; padding: 20px; border: 5px solid #ccc; width: 500px; background: #eee; >div.form-element < margin: 20px 0; >button < padding: 10px; font-size: 1.5rem; font-family: 'Lato'; font-weight: 100; background: yellowgreen; color: white; border: none; >p.success, p.error < color: white; font-family: lato; background: yellowgreen; display: inline-block; padding: 2px 10px; >p.error
В коде, приведенном выше, предусмотрено оформление заголовков и сообщений об ошибках валидации. Фрагменты HTML и CSS кода, рассмотренные выше, могут использоваться в качестве основы, поскольку ваш собственный проект может нуждаться в другом стиле оформления, а также в дополнительных полях ввода.
Создание таблицы с учетными данными и подключение к базе данных
Следующий шаг – создание таблицы базы данных, содержащей учетные данные пользователей. В нашем случае таблица состоит всего из четырех столбцов:
- Порядковый номер ID, который для каждого нового пользователя увеличивается автоматически.
- Уникальное имя пользователя.
- Адрес электронной почты.
- Пароль.
Для быстрого создания таблицы базы данных можно использовать следующий SQL-запрос:
CREATE TABLE `users` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `username` varchar(25) NOT NULL, `password` varchar(255) NOT NULL, `email` varchar(100) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=1;
Теперь создайте файл config.php и сохраните в нем приведенный далее код для подключения к базе данных:
catch (PDOException $e) < exit("Error: " . $e->getMessage()); > ?>
В приведенном выше коде замените название базы данных на то, которое вы используете для своего собственного сайта.
Исходный код для регистрации пользователей
Теперь пришла очередь написать код для регистрации пользователей. Главная функция этого кода – проверить, не зарегистрирован ли уже аналогичный адрес электронной почты в базе данных. Если нет, новое имя пользователя вместе с адресом его электронной почты и паролем передаются для сохранения в базе данных.
Сохраните приведенный далее код в начале файла registration.php :
prepare("SELECT * FROM users WHERE email=:email"); $query->bindParam("email", $email, PDO::PARAM_STR); $query->execute(); if ($query->rowCount() > 0) < echo 'Этот адрес уже зарегистрирован!
'; > if ($query->rowCount() == 0) < $query = $connection->prepare("INSERT INTO users(username,password,email) VALUES (:username,:password_hash,:email)"); $query->bindParam("username", $username, PDO::PARAM_STR); $query->bindParam("password_hash", $password_hash, PDO::PARAM_STR); $query->bindParam("email", $email, PDO::PARAM_STR); $result = $query->execute(); if ($result) < echo 'Регистрация прошла успешно!
'; > else < echo 'Неверные данные!
'; > > > ?>
На первом этапе выполнения кода включается config.php, начинается сессия. Так мы получаем возможность сохранить любую информацию для дальнейшего использования на всех страницах сайта.
Далее, с помощью $_POST[‘register’] мы проверяем, нажал ли пользователь кнопку «Регистрация». Следует помнить, что пароли нельзя сохранять в виде незашифрованного текста. Поэтому наш код использует функцию password_hash() и сохраняет пароль в хэшированном виде. Эта функция записывает пароль в базу данных в виде хэш-строки, состоящей из 60 случайных символов.
После этого мы проверяем, существует ли предоставленный пользователем адрес электронной почты в базе данных. Если это так, пользователь получит соответствующее сообщение. Если же такого email-адреса в базе данных, используемой сайтом, нет, вся введенная информация сохраняется в базе данных и пользователь видит сообщение об успешной регистрации.
Функция авторизации
На предыдущем этапе мы уже сохранили код для формы авторизации пользователей в системе. На этом этапе мы будем проверять, соответствуют ли введенные пользователем данные учетной записи, сохраненной в базе.
Приведенный далее код должен располагаться в начале файла login.php:
prepare("SELECT * FROM users WHERE username=:username"); $query->bindParam("username", $username, PDO::PARAM_STR); $query->execute(); $result = $query->fetch(PDO::FETCH_ASSOC); if (!$result) < echo 'Неверные пароль или имя пользователя!
'; > else < if (password_verify($password, $result['password'])) < $_SESSION['user_id'] = $result['id']; echo 'Поздравляем, вы прошли авторизацию!
'; > else < echo 'Неверные пароль или имя пользователя!
'; > > > ?>
Важно отметить, что мы не проверяем правильность имени и пароля одновременно. Поскольку пароль сохранен в хэшированном виде, сначала необходимо запросить хэш с помощью предоставленного имени пользователя. Когда мы получим хэш, можно будет проверить предоставленный пользователем пароль на соответствие хэшированному – с помощью функции password_verify().
Как только мы получаем подтверждение правильности пароля, мы назначаем переменную $_SESSION[‘user_id’] для ID пользователя из базы данных. При необходимости на этом этапе передаются и значения для других переменных.
Ограничение доступа к страницам
На большинстве сайтов, запрашивающих учетные данные посетителей, есть страницы, на которых зарегистрированные пользователи хранят свою личную информацию. Для защиты подобных страниц от несанкционированного доступа можно использовать переменные сессии. Если переменная сессии не создана, пользователь перенаправляется на страницу авторизации. Если переменная сессии создана, пользователь видит содержимое страницы:
Все, что нужно сделать для ограничения или предоставления доступа – это использовать в начале приведенного выше скрипта строку session_start().
Типичные ошибки и способы их решения
При использовании скрипта для ограничения доступа неавторизованных пользователей обычно возникают три типа ошибок.
Некорректное имя переменной
Чаще всего ошибки в работе скрипта связаны с неверными именами переменных – как правило, с использованием букв в неправильном регистре. Именно поэтому крайне важно придерживаться одного и того же шаблона при выборе имен. К примеру, ключи в функции $_POST основаны на значениях, полученных из полей ввода в формах. Это означает, что $_POST[‘USERNAME’] и $_POST[‘username’] получат разные значения.
«Заголовки уже отправлены»
Некоторые функции, например session_start() и header(), изменяют HTTP-заголовки. Поскольку PHP сбрасывает все заголовки перед выводом любых данных, важно вызывать все подобные функции до того, как вы начнете что-либо выводить – включая фрагменты сырого HTML или случайные пробелы перед открывающим тегом
Переменные сессии не сохраняются при переходах между страницами
Вы можете использовать переменные сессии только в том случае, если на странице осуществлен вызов функции session_start() . Если значения суперглобальной переменной $_SESSION вам не доступны, причина этого заключается в том, что вы забыли вызвать session_start() . Помните о том, что функцию надо вызывать перед выводом чего-либо на страницу сайта. В противном случае вы получите ошибку «Заголовки уже отправлены», рассмотренную выше.
Безопасный метод авторизации на PHP
Давайте посмотрим вокруг: форумы, интернет магазины, гостевые книги и т.д. используют регистрацию и последующую авторизацию пользователей. Можно даже сказать, что это почти необходимая функция каждого сайта (только если это не домашняя страничка Васи Пупкина или не визитная карточка, какой-нибудь небольшой компании). Сегодня я хочу поделиться со всеми новичками информацией, о том, как лучше это все реализовать.
Модель авторизации:
Клиент
Сервер MySQL
Таблица users
user_id (int(11))
user_login (Varchar(30))
user_password (varchar(32))
user_hash (varchar(32))
user_ip (int(10)) по умолчанию 0
При регистрации в базу данных записывается логин пользователя и пароль(в двойном md5 шифровании).
При авторизации сравнивается логин и пароль, если они верны, то генерируется случайная строка, которая хешируется и добавляется в БД в строку user_hash. Также записывается IP-адрес пользователя (но это у нас будет опциональным, так как кто-то сидит через Proxy, а у кого-то IP динамический. тут уже пользователь сам будет выбирать безопасность или удобство). В куки пользователя мы записываем его уникальный индетификатор и сгенерированный hash.
Почему надо хранить в куках хеш случайно сгенерированной строки, а не хеш пароля?
- Из-за невнимательности программиста во всей системе могут быть дырки, воспользовавшись этими дырками, злоумышленик может вытащить хеш пароля из БД и подставить его в свои куки, тем самым получить доступ к закрытым данным. В нашем же случае двойной хеш пароля ничем не сможет помочь хакеру, так как расшифровать его он не сможет (теоретически это возможно, но на это он потратит не один месяц, а может быть, и год), а воспользоваться этим хешем ему негде, ведь у нас при авторизации свой уникальный хеш прикрепленный к IP пользователя.
- Если злоумышленик вытащит трояном у пользователя уникальный хеш, воспользоваться им он также не сможет (разве, если только пользователь решил пренебречь своей безопастностью и выключил привязку к IP при авторизации).
Реализация
Структура таблицы `users` в базе данных ‘testtable’
CREATE TABLE `users` ( `user_id` int(11) unsigned NOT NULL auto_increment, `user_login` varchar(30) NOT NULL, `user_password` varchar(32) NOT NULL, `user_hash` varchar(32) NOT NULL default '', `user_ip` int(10) unsigned NOT NULL default '0', PRIMARY KEY (`user_id`) ) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1 ;
register.php
if(strlen($_POST[‘login’]) < 3 or strlen($_POST['login']) >30) < $err[] = "Логин должен быть не меньше 3-х символов и не больше 30"; >// проверяем, не сущестует ли пользователя с таким именем $query = mysqli_query($link, «SELECT user_id FROM users WHERE user_login='».mysqli_real_escape_string($link, $_POST[‘login’]).»‘»); if(mysqli_num_rows($query) > 0) < $err[] = "Пользователь с таким логином уже существует в базе данных"; >// Если нет ошибок, то добавляем в БД нового пользователя if(count($err) == 0) < $login = $_POST['login']; // Убераем лишние пробелы и делаем двойное хеширование $password = md5(md5(trim($_POST['password']))); mysqli_query($link,"INSERT INTO users SET user_login='".$login."', user_password='".$password."'"); header("Location: login.php"); exit(); >else < print "При регистрации произошли следующие ошибки:
«; foreach($err AS $error) < print $error."
«; > > > ?> Логин
Пароль
return $code; > // Соединямся с БД $link=mysqli_connect(«localhost», «mysql_user», «mysql_password», «testtable»); if(isset($_POST[‘submit’])) < // Вытаскиваем из БД запись, у которой логин равняеться введенному $query = mysqli_query($link,"SELECT user_id, user_password FROM users WHERE user_login='".mysqli_real_escape_string($link,$_POST['login'])."' LIMIT 1"); $data = mysqli_fetch_assoc($query); // Сравниваем пароли if($data['user_password'] === md5(md5($_POST['password']))) < // Генерируем случайное число и шифруем его $hash = md5(generateCode(10)); if(!empty($_POST['not_attach_ip'])) < // Если пользователя выбрал привязку к IP // Переводим IP в строку $insip = ", user_ip=INET_ATON('".$_SERVER['REMOTE_ADDR']."')"; >// Записываем в БД новый хеш авторизации и IP mysqli_query($link, «UPDATE users SET user_hash='».$hash.»‘ «.$insip.» WHERE user_id='».$data[‘user_id’].»‘»); // Ставим куки setcookie(«id», $data[‘user_id’], time()+60*60*24*30, «/»); setcookie(«hash», $hash, time()+60*60*24*30, «/», null, null, true); // httponly . // Переадресовываем браузер на страницу проверки нашего скрипта header(«Location: check.php»); exit(); > else < print "Вы ввели неправильный логин/пароль"; >> ?> Логин
Пароль
Не прикреплять к IP (небезопасно)
Логин
Пароль
Не прикреплять к IP(не безопасно)
Для защиты формы логина от перебора, можно использовать капчу или временную задержку на повторную авторизацию.
Автор: http://jiexaspb.habrahabr.ru/. Адаптация под PHP 5.5 и MySQL 5.7 KDG.
Куки с флагом HttpOnly не видны браузерному javascript-коду, а отправляются только на сервер. На практике у вас никогда не будет необходимости получать их содержимое в javascript. А вот злоумышленнику, нашедшему XSS – а XSS так или иначе когда-нибудь где-нибудь найдется – отсутствие HttpOnly на авторизационных куках доставит много радости.
Другие примеры авторизации на PHP: