Как на PHP реализовать простую систему авторизации по одноразовому коду из SMS или Email (OTP — One Time Password)?

OTP (One Time Password) — одноразовый пароль, который отправляется пользователю по SMS или Email и действует ограниченное время. Это надёжный способ двухфакторной или беспарольной авторизации.

## Общая схема работы OTP

1. Пользователь вводит номер телефона или email.
2. Сервер генерирует случайный код и сохраняет его в базе данных с временем истечения.
3. Код отправляется пользователю.
4. Пользователь вводит код на сайте.
5. Сервер сравнивает введённый код с сохранённым и проверяет срок действия.

## Структура таблицы в базе данных

sql
CREATE TABLE otp_codes (
id INT AUTO_INCREMENT PRIMARY KEY,
identifier VARCHAR(255) NOT NULL, — email или телефон
code VARCHAR(10) NOT NULL,
expires_at DATETIME NOT NULL,
is_used TINYINT(1) DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

## Генерация и сохранение OTP

php
function generateOTP(PDO $pdo, string $identifier): string {
$code = str_pad(random_int(0, 999999), 6, ‘0’, STR_PAD_LEFT);
$expiresAt = date(‘Y-m-d H:i:s’, time() + 300); // 5 минут

// Удаляем старые коды для этого пользователя
$stmt = $pdo->prepare(«DELETE FROM otp_codes WHERE identifier = ?»);
$stmt->execute([$identifier]);

// Сохраняем новый код
$stmt = $pdo->prepare(
«INSERT INTO otp_codes (identifier, code, expires_at) VALUES (?, ?, ?)»
);
$stmt->execute([$identifier, password_hash($code, PASSWORD_DEFAULT), $expiresAt]);

return $code;
}

> Важно: код лучше хранить в хешированном виде через `password_hash()`, чтобы защитить данные при утечке БД.

## Отправка кода по Email

php
function sendOTPByEmail(string $email, string $code): bool {
$subject = ‘Ваш код подтверждения’;
$message = «Ваш одноразовый код: $codenКод действует 5 минут.»;
$headers = ‘From: no-reply@example.com’;
return mail($email, $subject, $message, $headers);
// Для продакшена используйте PHPMailer или Symfony Mailer
}

## Отправка кода по SMS

Для SMS используйте сторонние сервисы: SMSC, SMS.ru, Twilio. Пример с Twilio:

php
use TwilioRestClient;

function sendOTPBySMS(string $phone, string $code): void {
$client = new Client(TWILIO_SID, TWILIO_TOKEN);
$client->messages->create($phone, [
‘from’ => TWILIO_PHONE,
‘body’ => «Ваш код: $code. Действует 5 минут.»
]);
}

## Проверка OTP

php
function verifyOTP(PDO $pdo, string $identifier, string $inputCode): bool {
$stmt = $pdo->prepare(
«SELECT code FROM otp_codes
WHERE identifier = ? AND is_used = 0 AND expires_at > NOW()»
);
$stmt->execute([$identifier]);
$row = $stmt->fetch();

if ($row && password_verify($inputCode, $row[‘code’])) {
// Помечаем код как использованный
$stmt = $pdo->prepare(
«UPDATE otp_codes SET is_used = 1 WHERE identifier = ?»
);
$stmt->execute([$identifier]);
return true;
}
return false;
}

## Дополнительные меры безопасности

— **Rate limiting**: ограничьте количество попыток (например, не более 5 за 15 минут).
— **Короткое время жизни**: 5–10 минут достаточно.
— **Одноразовость**: код должен стать недействительным после первого использования.
— **Логирование**: фиксируйте неудачные попытки ввода.
— **HTTPS**: передавайте код только по защищённому соединению.

Такая реализация подходит как для двухфакторной аутентификации, так и для полноценной беспарольной авторизации через Email или SMS.


Задайте вопрос нейросети

Не нашли ответ? Спросите ИИ — он подготовит развёрнутую статью.