Вопрос или проблема
Я хочу создать функцию, которая остановит процесс входа в WordPress и позволит пользователю ввести код OTP или форму для подтверждения перед полным входом. Я намерен сделать это перехватывание сразу после ввода пользователем электронной почты и пароля.
Вот что я попытался сделать:
add_filter( 'authenticate', 'smyles_check_custom_auth', 10, 3 );
function smyles_check_custom_auth( $user, $username, $password ){
$otp_check = 'bad'; // переменная, возвращаемая из запроса, но для тестирования использую 'bad'
if( !$otp_check == 'good' ){
return confirm_form();
}
elseif($otp_check == 'good'){
return $user;
}
return new WP_Error( __( 'Ошибка проверки OTP' ) );
}
Однако это не сработало, оно просто останавливает форму от проверки без каких-либо сообщений об ошибках, если я устанавливаю приоритет 20,3.
Моя цель – сначала проверить имя пользователя и пароль, а затем кнопка отправки и поля имени пользователя и пароля будут отключены, и покажется мой код подтверждения OTP. Как только пользователь подтвердит правильный OTP, процесс входа продолжится, что будет перенаправлением, надеюсь, в админку. Если я устанавливаю уровень приоритета на 10, 3, форма отправляется, и пользователь входит, независимо от введенного кода.
Рабочий процесс выглядит так:
- Пользователь вводит свое имя пользователя и пароль.
- Wp_authenticate() проверяет, если имя пользователя и пароль совпадают с пользователем в таблице wp_users.
- Если совпадает, тогда вызывается мой метод, который отправляет OTP на электронную почту пользователя.
- Вызывается фильтр wp_disable_username_and_password_boxes или полей.
- Вызывается мой метод confirmotp(), который является простой HTML-формой для ввода кода OTP.
- Мой метод verify() проверяет код OTP и возвращает различные ошибки, такие как количество цифр, является ли числом, ошибки несовпадения и т.д.
- Но если возвращаемое значение из моего запроса проверки OTP истинно или нормально, тогда…
- Вызывается перенаправление на wpadmin, что является частью процесса входа.
Таким образом, вся моя проблема заключается в том, чтобы узнать хук, который я могу использовать в моем confirm_form(), чтобы он выполнялся после проверки имени пользователя и пароля, но до вызова действия wpsignon(). Просто промежуточный перехват.
Да, есть фильтр authenticate
, в который вы можете подключиться в функции wp_authenticate
и вернуть WP_Error
, если вход не удался.
/**
* Фильтрует, являются ли учетные данные пользователя действительными.
*
* Объект WP_User возвращается, если учетные данные аутентифицируют пользователя.
* WP_Error или null в противном случае.
*
* @since 2.8.0
* @since 4.5.0 `$username` теперь принимает адрес электронной почты.
*
* @param null|WP_User|WP_Error $user WP_User, если пользователь аутентифицирован.
* WP_Error или null в противном случае.
* @param string $username Имя пользователя или адрес электронной почты.
* @param string $password Пароль пользователя
*/
$user = apply_filters( 'authenticate', null, $username, $password );
Вот как WordPress внутренне проверяет имя пользователя и пароль, это стандартные фильтры:
add_filter( 'authenticate', 'wp_authenticate_username_password', 20, 3 );
add_filter( 'authenticate', 'wp_authenticate_email_password', 20, 3 );
add_filter( 'authenticate', 'wp_authenticate_spam_check', 99 );
Я рекомендую устанавливать ваш фильтр с приоритетом 10 или ниже 20 (что происходит, когда проверяются имя пользователя и пароль), чтобы ваша проверка выполнялась первой.
Если ваш тест проходит, просто верните первую переданную переменную, например:
add_filter( 'authenticate', 'smyles_check_custom_auth', 10, 3 );
function smyles_check_custom_auth( $user, $username, $password ){
$otp_check = false;
if( $otp_check ){
return $user;
}
return new WP_Error( __( 'Ошибка проверки OTP' ) );
}
Ответ или решение
Для добавления пользовательской аутентификации в процессы входа и регистрации WordPress, в частности для проверки OTP (одноразового пароля) после валидации имени пользователя и пароля, необходимо разработать несколько функций и использовать соответствующие хуки. Это поможет реализовать необходимый вам рабочий процесс. Ниже представлена полная инструкция по реализации данного функционала.
Шаг 1: Использование фильтра authenticate
WordPress предоставляет фильтр authenticate
, который позволяет перехватить процесс аутентификации. Этот фильтр вызывается после проверки имени пользователя и пароля. Мы будем использовать его для добавления проверки OTP.
add_filter('authenticate', 'smyles_custom_auth', 10, 3);
function smyles_custom_auth($user, $username, $password) {
// Сначала проверяем, были ли введены корректные имя пользователя и пароль
if (is_wp_error($user)) {
return $user; // Если произошла ошибка в аутентификации, просто возвращаем ее
}
// Отправляем OTP пользователю, если он успешно прошел аутентификацию
smyles_send_otp($user->user_email);
// Сохраняем информацию о пользователе и статусе OTP в сессии или временной таблице
$_SESSION['smyles_pending_user'] = $user->ID;
$_SESSION['smyles_otp_sent'] = true;
return new WP_Error('otp_required', __('Пожалуйста, введите код OTP для завершения входа.'));
}
Шаг 2: Отправка OTP на email
Создаем функцию для отправки OTP кода на электронную почту пользователя.
function smyles_send_otp($email) {
$otp = wp_rand(100000, 999999); // Генерируем 6-значный OTP
// Отправляем OTP на email
wp_mail($email, 'Ваш OTP код', 'Ваш код OTP: ' . $otp);
// Сохраняем OTP код в сессии или базе данных
$_SESSION['smyles_otp'] = $otp;
}
Шаг 3: Валидация OTP
Создайте HTML-форму для ввода OTP и обработчик для ее проверки.
function smyles_verify_otp() {
if (isset($_POST['otp_submit'])) {
$input_otp = sanitize_text_field($_POST['otp_code']);
if ($input_otp === $_SESSION['smyles_otp']) {
$user_id = $_SESSION['smyles_pending_user'];
// Удаляем временные данные из сессии
unset($_SESSION['smyles_pending_user']);
unset($_SESSION['smyles_otp_sent']);
unset($_SESSION['smyles_otp']);
return get_userdata($user_id); // Возвращаем пользователя для продолжения входа
} else {
return new WP_Error('otp_invalid', __('Неверный код OTP.'));
}
}
}
Шаг 4: Отображение формы для ввода OTP
Вам нужно внедрить форму для ввода OTP, которая будет отображаться пользователю после успешной аутентификации с именем пользователя и паролем.
function smyles_display_otp_form() {
if (isset($_SESSION['smyles_otp_sent']) && $_SESSION['smyles_otp_sent']) {
?>
<form method="post">
<label for="otp_code">Введите код OTP:</label>
<input type="text" name="otp_code" required>
<input type="submit" name="otp_submit" value="Подтвердить">
</form>
<?php
}
}
Шаг 5: Интеграция и тестирование
Важно протестировать весь процесс: введение имени пользователя и пароля, получение и ввод OTP, а затем выполнить вход.
Заключение
Таким образом, вам удалось создать собственную систему аутентификации на основе проверки OTP в WordPress. Важно убедиться, что вы сохраняете данные о пользователе и OTP безопасно, используя сессии или временные таблицы в базе данных. Не забывайте также об обработке ошибок и безопасности, чтобы защитить свою систему от потенциальных угроз.
Рекомендую вам периодически проверять вашу систему аутентификации на наличие уязвимостей и соответствовать лучшим практикам безопасности.