Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. PHP
Code

Создание расширенной утилиты восстановления пароля

by
Difficulty:IntermediateLength:LongLanguages:

Russian (Pусский) translation by Svetlana (you can also view the original English article)

В моем последнем учебнике «Лучший Логин входа в систему» ​​несколько человек прокомментировали, как они хотели бы видеть учебник по восстановлению пароля, который вы не всегда видите в учебниках по доступу пользователей. Учебник, который я привожу вам сегодня, будет иметь дело только с этим. Используя mySQLi, мы научимся восстанавливать незашифрованные и (односторонние) зашифрованные пароли.

Введение

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

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

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

ВАЖНОЕ ПРИМЕЧАНИЕ. В этом руководстве вместо mysql используется интерфейс mysqli. Хотя в документации PHP написано, что она должна работать, я не смог успешно использовать классы mysqli, пока не обновился с 5.1.4 до 5.2.9. Если вы получаете ошибки об использовании «неподдерживаемого буфера», попробуйте обновить. Вам также может понадобиться изменить файл php.ini для загрузки расширения mysqli, если вы видите ошибки, связанные с отсутствием поиска класса mysqli.

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

Шаг 1: Таблицы базы данных

После создания новой базы данных нам нужно создать три таблицы:

Database tables

Таблица recoveryemails_enc содержит информацию об электронных письмах, которые отправляются, чтобы позволить пользователям сбросить пароли (например, ключ безопасности, идентификатор пользователя и срок действия). Таблицы пользователей содержат информацию о пользователях. Если вы следуете зашифрованному примеру, используйте таблицу users_enc, в противном случае используйте таблицу users.

Если у вас уже есть таблица пользователей, вам нужно будет добавить поля контрольного вопроса и ответа. Поле вопроса будет содержать целое число, равное контрольному вопросу в массиве, а поле ответа содержит ответ типа varchar. Секретный вопрос используется как подтверждение перед отправкой пароля по электронной почте. Вот код, который вы должны запустить для создания таблиц (также доступен в sql.txt в загрузке):

Шаг 2: База данных включает

Database Connection

Нам нужно создать включаемый файл, чтобы мы могли подключиться к нашей базе данных. Для взаимодействия с базой данных мы будем использовать mysqli, который обеспечивает объектно-ориентированный подход к взаимодействию с базой данных. Создайте файл под названием assets / php / database.php. Мы добавим следующий код (заменим значения переменных информацией, подходящей для вашей ситуации с хостингом):

В первой строке кода мы вызываем session_start (), на самом деле мы не будем использовать переменные сеанса, но вам понадобится сеанс как часть системы входа пользователя. Затем мы вызываем ob_start () для запуска буфера вывода.

Строки 4-8 настраивают наши переменные для подключения к серверу. Затем мы создаем новый объект mysqli, передавая ему наши переменные. В оставшейся части нашего скрипта $ mySQL позволит нам взаимодействовать с базой данных по мере необходимости.

Mysqli обрабатывает события ошибок немного по-другому, поэтому мы должны проверить свойство connect_error после подключения и вывести сообщение об ошибке, если что-то пошло не так. То же самое относится и к выполнению запросов; мы должны проверить свойство error (ошибка)нашего запроса или объекта соединения, чтобы проверить наличие ошибок.

Шаг 3: Создайте страницу забытого пароля

Давайте начнем с этого шага, создав файл ForgotPass.php. Затем мы добавим этот код к нему:

Этот HTML дает нам хорошую основу для дальнейшего развития и дает нам следующее:

Page Tamplate

Затем добавьте этот код в самый верх страницы, над HTML, который мы только что ввели:

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

После этого мы проверяем некоторые переменные сессии. Если переменная блокировки сеанса имеет значение true, и с момента ее блокировки прошло более 900 секунд (15 минут), мы хотим завершить блокировку, что для нас делают строки 7 и 8.

Затем мы создаем блок if, который проверяет, было ли что-либо опубликовано на странице. Вы также можете видеть, что мы проверяем, чтобы $ _GET ['a'] не был установлен, эта переменная будет установлена, когда пользователь нажимает на ссылку в своем электронном письме восстановления, поэтому, если это происходит, мы можем пропустить после проверки. Также в логическом блоке мы гарантируем, что для переменной блокировки не установлено значение true.

Оказавшись внутри блока if, мы используем переключатель ($ _ POST ['subStep']), чтобы проверить, какой этап формы был отправлен. Мы выполним три этапа: Шаг 1 означает, что мы только что ввели имя пользователя или адрес электронной почты, для которого мы хотим сбросить пароль. Для этого мы вызываем функцию checkUNEmail (), которую мы напишем сейчас. Эта функция возвращает массив, который имеет логическое значение для определения, был ли пользователь найден, и целое число userID, если пользователь был найден. Строка 17 проверяет, вернула ли пользовательская проверка ложь (пользователь не был найден), если так, мы устанавливаем флаг ошибки и переменную $ show (показывать), чтобы увидеть сообщение «Пользователь не найден». Если пользователь был найден, мы должны показать форму с вопросом о безопасности и установить $ securityUser (безопасный пользователь), чтобы мы знали, для какого пользователя загружать вопрос.

На втором этапе мы представили секретный вопрос. Первое, что мы делаем здесь, это проверяем, чтобы были возвращены и идентификатор пользователя, и ответ. Если какой-либо из них был опущен, мы снова отображаем форму секретного вопроса. Если оба значения были включены, мы вызываем функцию, чтобы проверить ответ по базе данных. Эта функция возвращает простое логическое значение. Если на вопрос был дан правильный ответ, мы покажем страницу успеха, отправим электронное письмо с сбросом и установим счетчик неверных записей равным 0. Если на вопрос был получен неправильный ответ, мы снова отобразим страницу вопроса, а также увеличим счетчик неверных ответов.

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

ПРИМЕЧАНИЕ. Если вы используете незашифрованные пароли, вы можете пропустить случай 3 выше. Это метод, который сохраняет новый пароль после его сброса. Поскольку мы можем отправлять незашифрованные пароли по электронной почте, им не нужно их сбрасывать.

Теперь мы добавим блок else к этому же блоку if сверху:

Этот блок ещё определяет, установлен ли $ _GET ['a'], что означает, что пользователь зашел на страницу по ссылке сброса электронной почты. Если мы выяснили, что они нажали на ссылку, мы хотим проверить, является ли ключ электронной почты действительным, используя checkEmailKey () (проверка емейл вводов). Если ключ не найден или недействителен, это возвращает логическую ложь, и мы показываем нетрудоспособное ключевое сообщение. Если ключ действителен, однако, это возвращает массив, вне (так мы знаем который пароль пользователя снова для установки) которого мы можем схватить userid.

ПРИМЕЧАНИЕ. Если вы используете незашифрованные пароли, вы можете пропустить блок elseif. Это имеет дело с показом формы изменения пароля после щелкания по связи в электронной почте.

Второй, если там проверка по блокам, чтобы посмотреть, если пользователь ответил на вопрос безопасности неправильно более чем 3 раза. Если они имеют, мы устанавливаем lockout переменную к истине, и устанавливаем lockout время, которое является временем, когда блокировка вступила в силу. Заметьте, что, если lockout время уже определено, мы будем пользоваться этой переменной, но в противном случае, мы будем производить новое время.

Урегулирование speedlimit важно для безопасности. По большей части это будет служить, чтобы удерживать людей только, сидя там и пробуя догадаться ответ на вопросы безопасности. Это может также помочь воспрепятствовать ботам передача формы снова и снова. Главный недостаток этого метода есть, что пользователь может только удалить домашнее печенье Phpsess_id, а затем они могут начать. Если вы хотите очень безопасного решения, вы смогли добавить, что 'lockout' флаг к пользовательскому столу, и когда они ответили неправильно 3 разам, устанавливает, что флаг к истине. Затем вы можете написать код для блокировки, если они попытаются получить доступ к учетной записи.

Шаг 4: Функциональный файл

Functions

Теперь давайте создадим файл assets / php / functions.php для хранения всех функций, на которые мы ссылались ранее. Теперь давайте рассмотрим их по несколько раз:

ПРИМЕЧАНИЕ. В примерах файлов в зашифрованном примере используется таблица 'users_enc', в то время как в незашифрованном примере используется таблица 'users', поэтому имя таблицы будет изменяться в ваших функциях в зависимости от используемой версии.

В верхней части файла мы хотим определить PW_SALT, который является соль, которую мы будем использовать для шифрования паролей во всем. Первая функция берет значения имени пользователя и пароля из $ _POST и проверяет, существует ли соответствующий пользователь в базе данных. Первое, что нам нужно сделать, это сделать $ mySQL глобальным, чтобы мы могли получить доступ к базе данных. Мы также создаем общий массив ошибок, который мы будем возвращать, если пользователь не найден. Затем мы проверяем, есть ли значение для письма. Если это так, мы создаем подготовленный оператор MySQLi. Преимуществом использования готовых операторов является безопасность, особенно когда речь идет о пользовательском вводе, весь процесс аналогичен использованию sprintf ().

Обратите внимание, что мы вызываем метод -> prepare () (подготовка) с нашим SQL-запросом в качестве параметра, и используем вопросительные знаки, куда будут идти наши переменные. Также обратите внимание, что мы не ставим кавычки вокруг вопросительных знаков (даже для строки). Это то, что позволяет нам параметризировать оператор. mySQLi :: prepare () вернет правильно, если инструкция была успешно создана. Если он был создан, нам нужно привязать параметры к нашему запросу, используя mySQLi :: bind_param (). Эта функция принимает как минимум два аргумента. Первая - это строка букв, которые представляют типы данных данных, которые будут связаны. Остальные аргументы - это переменные, которые вы хотите видеть в каждом параметре. В нашем случае мы используем 's' (для строки) и $ email, поскольку эта переменная имеет адрес электронной почты. Обратите внимание, что порядок важен, поэтому первый знак вопроса в вашем запросе соответствует первой букве в строке формата и первой переменной.

Затем нам нужно вызвать -> execute () и -> store_result (). Эти два метода запускают подготовленный запрос и сохраняют его в памяти до освобождения. Затем мы проверяем количество возвращаемых строк, чтобы убедиться, что пользователь был найден. -> bind_result () очень похож на -> bind_param () за исключением противоположного направления. Это позволяет нам взять возвращенное значение из результата и отобразить его в локальной переменной. Переменные присваиваются в зависимости от их порядка в наборе результатов. Локальная переменная фактически не записывается, пока мы не вызовем -> fetch (), после того как мы вызовем -> fetch (), переменная $ userID будет содержать переменную из базы данных. Затем мы используем -> close () для запроса, чтобы освободить результат. Наконец, мы вернем массив, который содержит логическое значение для успеха и целое число для идентификатора пользователя.

getSecurityQuestion () принимает идентификатор пользователя и возвращает его контрольный вопрос в виде строки. Еще раз, мы делаем глобальный $ mySQL. Затем мы создаем массив из 6 различных возможных вопросов безопасности. Используя метод, аналогичный описанному выше, мы видим, какой секретный вопрос выбрал пользователь, затем возвращаем этот индекс из массива.

checkSecAnswer () принимает идентификатор пользователя и строковый ответ и проверяет базу данных, чтобы убедиться, что это правильно. Обратите внимание, что мы преобразуем переданный ответ и ответ базы данных в нижний регистр, чтобы увеличить шансы на совпадение (необязательно для вас). Это отличный пример многопараметрического оператора. Обратите внимание на порядок аргументов в методе bind_param (). Эта функция вернет истину, если найдет запись, в которой идентификатор пользователя и ответ совпадают с тем, что было передано. В противном случае он вернет false.

Эта функция заботится об отправке электронного письма для сброса пароля. Мы начинаем с выполнения запроса SQL, чтобы получить имя пользователя и адрес электронной почты переданного пользователя. После привязки параметров и результата мы закрываем запрос. В целях безопасности мы хотим, чтобы сгенерированная нами ссылка работала в течение 3-х  дней. Для этого мы создаем новую дату, которая будет через 3-и дня. Их, используя несколько значений, которые передаются, дату, случайное число и нашу соль, мы генерируем хеш MD5, который будет нашим ключом безопасности. Из-за каждой изменяющейся будущей даты и случайного числа мы должны быть уверены, что каждый раз мы получаем абсолютно случайный ключ. Затем мы строим запрос SQL, чтобы вставить его в базу данных. После выполнения запроса мы создаем ссылку, которая будет отправлена ​​в электронном письме. Мы хотим включить 'a = recovery' и наш ключ, а также userID, который мы base64_encode () и urlencode (), чтобы сделать его недоступным для чтения. Как только ссылка сгенерирована, мы создаем оставшуюся часть нашего электронного письма и отправляем его.

ПРИМЕЧАНИЕ. Если вы используете незашифрованный пример, вы хотите изменить текст сообщения, чтобы вместо него распечатать переменную $ pword вместо ссылки для сброса пароля.

ПРИМЕЧАНИЕ. Если вы разрабатываете это на локальном сервере, маловероятно, что у вас установлен SMTP, поэтому вы не сможете отправлять почту. Вот почему мы используем команду @mail () (для предотвращения сообщений об ошибках). Также по этой причине эта функция возвращает строку сообщения, чтобы его можно было распечатать на экране. Теперь для последних 3 функций:

Первая функция проверяет ключ электронной почты, который был передан. Мы создаем строку даты для представления сегодняшней даты (поэтому мы знаем, истек ли срок действия ключа). Затем наш SQL проверяет, существуют ли какие-либо записи для ключа, который соответствует переданному пользователю, ключу безопасности и что срок действия истек уже сейчас. Если такой ключ существует, мы возвращаем массив с идентификатором userID или false в противном случае.

Функция updateUserPassword () заботится об изменении действительного пароля в базе данных. Сначала мы проверяем ключ электронной почты на соответствие переданной информации о пользователе и ключе, чтобы убедиться в безопасности. Мы генерируем новый пароль, комбинируя переданный пароль и ранее определенную соль, а затем запускаем md5 () для этой строки. Затем мы выполняем наше обновление. После этого мы удаляем запись ключа восстановления из базы данных, чтобы его нельзя было использовать снова.

ПРИМЕЧАНИЕ. Функция updateUserPassword () не требуется в незашифрованном примере, поскольку мы не меняем их пароль.

getUserName () - это просто служебная функция для получения имени пользователя с идентифицированным идентификатором пользователя. Он использует базовый оператор SQL, как и другие.

Шаг 5: заполните страницу забытого пароля

Теперь, когда у нас есть функции, которые нам нужны, мы добавим еще несколько в ForgotPass.php. Добавьте этот код внутри div с идентификатором "page":

Этот код будет иметь дело с отображением всех элементов интерфейса. Мы начнем с изучения переменной $ show, описанной ранее, с помощью switch (). Как вы, возможно, помните из предыдущего, существует множество различных значений, которые может иметь $ show, поэтому мы должны создать регистр для каждого из них. В первом случае, «emailForm», пользователь вводит либо имя пользователя, либо адрес электронной почты, для которого он хочет восстановить пароль. В основном нам нужны два текстовых поля и скрытый ввод, чтобы мы знали, какой шаг мы отправили. Существует также блок if ($ error == true), который будет отображать сообщение об ошибке, если флаг $ error имеет значение true.

Email Form

Второй случай - «securityForm». Это где секретный вопрос будет отображаться. Вы можете видеть, что у нас также есть сообщение об ошибке, и мы используем getSecurityQuestion (), чтобы напечатать контрольный вопрос. Затем у нас есть вход для ответа, а также шаг и идентификатор пользователя.

Security Question

Сообщение для «userNotFound» - это просто текстовое сообщение, которое сообщает пользователю, что запись не была найдена.

«SuccessPage» отображается, когда на секретный вопрос был дан правильный ответ и электронное письмо было отправлено. Обратите внимание, что мы распечатали сообщение электронной почты в нижней части этого приглашения, вы не будете делать это в производственной среде, потому что тогда вы даете человеку мгновенный доступ к коду безопасности, предназначенному только для зарегистрированного пользователя.

Email

Давайте продолжим с этим кодом:

Продолжая оператор switch, у нас есть «coverForm », который отображает форму для изменения пароля. Мы распечатываем имя пользователя и сообщение об ошибке, если это необходимо. Затем у нас есть поля ввода для пароля и пароля подтверждения, шага отправки, идентификатора пользователя и ключа безопасности из электронного письма. Для ключа и идентификатора пользователя e использует специальный синтаксис if (), чтобы убедиться, что мы получаем переменную из правильного места. Если переменная querystring равна нулю, мы посмотрим на переменные post, чтобы убедиться, что здесь у нас всегда есть значение.

Change Password

Затем «invalidKey» означает, что предоставленный ключ не существует или срок его действия истек. Сообщение «speedLimit» отображается, если пользователь заблокирован из-за слишком большого количества неправильных ответов. Наконец, мы вызываем ob_flush () для отправки страницы в браузер и $ mySQL-> close () для отключения от базы данных.

ПРИМЕЧАНИЕ. Сообщения «recoveryForm» и «invalidKey», описанные выше, не нужны для незашифрованных паролей.

Заключение

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

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

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

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

  • Подпишитесь на нас в Твиттере или подпишитесь на RSS-канал NETTUTS, чтобы получать ежедневные обзоры и статьи о веб-разработке.


Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.