Диагностика задачи: зачем нужна авторизация через SMS в WooCommerce
Стандартная авторизация в WooCommerce и WordPress чаще всего реализована через email и пароль. Однако для интернет-магазинов важно повысить безопасность и упростить процесс входа, особенно на мобильных устройствах. Авторизация через SMS с одноразовым паролем (OTP) решает эту задачу, минимизируя риски взлома пароля и сокращая количество забытых паролей. В этой статье разберём, как по шагам реализовать такую систему без сторонних плагинов с примерами кода.
Как работает OTP-авторизация: общий принцип
Пользователь вводит номер телефона на странице входа. После отправки формы генерируется одноразовый код (обычно 4–6 цифр), который отправляется через SMS. Пользователь вводит код на сайте, и после успешного подтверждения происходит вход в систему с привязкой к пользователю WooCommerce/WordPress.
Основные компоненты решения:
- Форма ввода номера телефона и формы подтверждения кода.
- Генерация и хранение OTP с ограничением по времени жизни.
- Отправка SMS (через API SMS-провайдера).
- Обработка подтверждения OTP и авторизация пользователя.
Пошаговое решение: реализация авторизации через SMS с OTP в WooCommerce
1. Добавляем форму входа с номером телефона
Создайте файл шаблона или добавьте код в functions.php вашей дочерней темы, чтобы заменить стандартную форму входа WooCommerce на форму с полем телефона.
add_shortcode('wc_sms_login_form', function() {
ob_start();
?>
<form id="sms-login-form" method="post">
<label for="phone">Введите номер телефона:</label><br>
<input type="tel" id="phone" name="phone" pattern="\+?\d{10,15}" required>
<button type="submit" name="send_otp">Получить код</button>
</form>
<form id="otp-confirm-form" method="post" style="display:none;">
<label for="otp">Введите код из SMS:</label><br>
<input type="text" id="otp" name="otp" pattern="\d{4,6}" required>
<button type="submit" name="verify_otp">Войти</button>
</form>
<div id="sms-login-message"></div>
<script>
const smsForm = document.getElementById('sms-login-form');
const otpForm = document.getElementById('otp-confirm-form');
const messageDiv = document.getElementById('sms-login-message');
smsForm.addEventListener('submit', e => {
e.preventDefault();
const phone = smsForm.phone.value;
fetch('', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'send_otp=1&phone=' + encodeURIComponent(phone)
}).then(res => res.json()).then(data => {
messageDiv.textContent = data.message;
if(data.success) {
smsForm.style.display = 'none';
otpForm.style.display = 'block';
}
});
});
otpForm.addEventListener('submit', e => {
e.preventDefault();
const otp = otpForm.otp.value;
const phone = smsForm.phone.value;
fetch('', {
method: 'POST',
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
body: 'verify_otp=1&phone=' + encodeURIComponent(phone) + '&otp=' + encodeURIComponent(otp)
}).then(res => res.json()).then(data => {
messageDiv.textContent = data.message;
if(data.success) {
window.location.reload();
}
});
});
</script>
<?php
return ob_get_clean();
});2. Обработка отправки OTP и верификация кода
Добавим обработчики в functions.php, чтобы генерировать OTP, сохранять его в пользовательском мета и отправлять SMS. Для отправки SMS используйте API вашего провайдера, например Twilio, SMS.ru, или любой другой.
add_action('init', function() {
if(isset($_POST['send_otp']) && isset($_POST['phone'])) {
header('Content-Type: application/json');
$phone = sanitize_text_field($_POST['phone']);
// Поиск пользователя по номеру телефона (в user meta 'phone')
$user = get_users(array(
'meta_key' => 'phone',
'meta_value' => $phone,
'number' => 1,
'count_total' => false
));
if(empty($user)) {
echo json_encode(['success' => false, 'message' => 'Пользователь с таким номером не найден']);
exit;
}
$user = $user[0];
// Генерация OTP
$otp = wp_rand(100000, 999999);
update_user_meta($user->ID, 'sms_otp', $otp);
update_user_meta($user->ID, 'sms_otp_time', time());
// Отправка SMS (пример для SMS.ru, замените на вашего провайдера)
$api_key = 'ВАШ_API_КЛЮЧ';
$text = 'Ваш код подтверждения: ' . $otp;
$url = 'https://sms.ru/sms/send?api_id=' . $api_key . '&to=' . rawurlencode($phone) . '&msg=' . rawurlencode($text);
$response = wp_remote_get($url);
if(is_wp_error($response)) {
echo json_encode(['success' => false, 'message' => 'Ошибка отправки SMS']);
exit;
}
echo json_encode(['success' => true, 'message' => 'Код отправлен на ваш телефон']);
exit;
}
if(isset($_POST['verify_otp']) && isset($_POST['phone']) && isset($_POST['otp'])) {
header('Content-Type: application/json');
$phone = sanitize_text_field($_POST['phone']);
$otp = sanitize_text_field($_POST['otp']);
$user = get_users(array(
'meta_key' => 'phone',
'meta_value' => $phone,
'number' => 1,
'count_total' => false
));
if(empty($user)) {
echo json_encode(['success' => false, 'message' => 'Пользователь не найден']);
exit;
}
$user = $user[0];
$saved_otp = get_user_meta($user->ID, 'sms_otp', true);
$otp_time = get_user_meta($user->ID, 'sms_otp_time', true);
if(!$saved_otp || !$otp_time || (time() - $otp_time) > 300) { // 5 минут
echo json_encode(['success' => false, 'message' => 'Код устарел или отсутствует']);
exit;
}
if($otp !== $saved_otp) {
echo json_encode(['success' => false, 'message' => 'Неверный код']);
exit;
}
// Удаляем OTP после успешной проверки
delete_user_meta($user->ID, 'sms_otp');
delete_user_meta($user->ID, 'sms_otp_time');
// Авторизация пользователя
wp_clear_auth_cookie();
wp_set_current_user($user->ID);
wp_set_auth_cookie($user->ID);
echo json_encode(['success' => true, 'message' => 'Авторизация успешна']);
exit;
}
});Проверка результата: как убедиться, что авторизация работает
- Добавьте шорткод
[wc_sms_login_form]на тестовую страницу. - Попробуйте ввести номер телефона, зарегистрированный у пользователя (укажите его в user meta с ключом
phone). - Проверьте получение SMS с OTP (важно, чтобы SMS API был настроен корректно).
- Введите код на форме подтверждения и убедитесь, что происходит вход в аккаунт без ввода пароля.
- После успешного входа проверьте, что
is_user_logged_in()возвращает true, и пользователь видит свой профиль.
Частые ошибки и их устранение
- Пользователь не найден по номеру телефона: убедитесь, что у всех ваших пользователей есть мета ключ
phoneс корректным номером. Для массового добавления можно использовать SQL-запрос или WP CLI. - SMS не отправляются: проверьте правильность API ключа, формат номера, и ответы от SMS-провайдера. Для отладки используйте
error_log(print_r($response,true)). - Код OTP не проходит проверку: убедитесь, что время жизни кода (5 минут в примере) не истекло, и что коды сравниваются строго (строгое сравнение строк).
- Форма не переключается между вводом номера и вводом кода: проверьте корректность JS-кода и отсутствие конфликтов с другими скриптами.
Практические советы по безопасности и производительности
- OTP должен быть одноразовым и иметь ограниченный срок действия (5 минут оптимально).
- Храните OTP в зашифрованном виде, если требуется дополнительная безопасность (например, через
hash_hmac). - Ограничьте количество попыток ввода OTP, чтобы избежать перебора кодов.
- Используйте nonce и проверку прав пользователя при обработке форм, чтобы избежать CSRF-атак.
- Кэширование страницы с формой отключите, чтобы всегда отображалась актуальная форма.
- Для повышения удобства можно интегрировать WPShop Clearfy Pro для удаления лишних дублей и оптимизации сайта после внедрения новых функций.
Сравнение вариантов реализации авторизации через SMS в WooCommerce
| Метод | Плюсы | Минусы | Пример |
|---|---|---|---|
| Плагин (например, OTP Verification) | Быстрая настройка, поддержка функционала | Зависимость от стороннего кода, возможные конфликты | Clearfy |
| Собственная реализация на PHP и JS | Полный контроль, гибкость, минимальные зависимости | Требует разработки и поддержки, нужно настроить SMS API | Код в статье выше |
| Использование внешних сервисов авторизации (Auth0, Firebase) | Надёжность, масштабируемость, готовые решения | Зависимость от сторонних сервисов, стоимость | Интеграция через SDK и WP плагины |