Привет, Хабр! Всегда было любопытно, как автоматизировать отправку кодов через SMS для второго этапа подтверждения личности при входе пользователя. Мы с коллегой решили разработать простой, но эффективный инструмент, который мог бы автоматически генерировать и отправлять SMS с кодами пользователя. Для реализации этой задачи выбрали API сервиса МТС Exolve.
Этот сервис упрощает рассылку SMS и предоставляет удобные инструменты для работы с сообщениями. Также Exolve добавляет новым пользователям 300 рублей на счет для тестирования платформы, что в целом достаточно для того, чтобы оценить все функции сервиса без начальных инвестиций.
Как начать работу
Первый шаг для старта работы с Exolve — регистрация на официальном сайте. После неё появится доступ к личному кабинету, где можно управлять настройками и использовать различные функции платформы.
Для начала работы с API, необходимо создать приложение. Это делается во вкладке Приложения в аккаунте. Создание приложения позволит сгенерировать API ключи, необходимые для работы с SMS.
После создания приложения переходим во вкладку Ключи в настройках приложения, чтобы сгенерировать новый API ключ. Ключ будет использоваться для аутентификации ваших запросов к API Exolve.
Для отправки SMS нужен номер. Для этого используем начисленные нам при регистрации 300 рублей для тестирования платформы. Во вкладке Номера можно выбрать и приобрести номер. Также есть возможность приобрести номер по региону во вкладке фильтров.
Кратко про SMS API
SMS API Exolve имеет разнообразные методы, некоторые из них:
Метод SendSMS
Метод позволяет отправить SMS-сообщение. Нужно выполнить POST-запрос с параметрами, указывающими номер или альфа-имя отправителя. Номер в данном случае — тот номер, который мы купили, его нужно указать в формате 71234567891. .Также нужно указать номер получателя и текст сообщения. Например, запрос на Go можно сделать так:
func sendSMS(number, destination, text string) { requestData := map[string]string{ "number": number, "destination": destination, "text": text, } jsonData, _ := json.Marshal(requestData) req, _ := http.NewRequest("POST", "https://api.exolve.ru/messaging/v1/SendSMS", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer ваш_API_ключ") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() // обработка ответа... }
Метод GetList
Метод позволяет получить данные об отправленных и полученных SMS. Он также осуществляется через POST-запрос, где можно указать фильтры для поиска сообщений:
func getList() { // параметры запроса можно задать в зависимости от потребностей requestData := map[string]interface{}{} jsonData, _ := json.Marshal(requestData) req, _ := http.NewRequest("POST", "https://api.exolve.ru/messaging/v1/GetList", bytes.NewBuffer(jsonData)) req.Header.Set("Authorization", "Bearer ваш_API_ключ") req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() // Обработка ответа... }
Помимо отправки и получения информации о сообщениях, есть методы для управления альфа-именами GetAlphaNames, создания и управления шаблонами SMS CreateTemplate, GetTemplate и GetTemplate . Подробнее с документаций можно ознакомиться здесь.
А пока перейдем к написанию генератора кодов.
Создание генератора кода
Создадим некое веб-приложение на Go, которое использует SMS API для отправки кодов верификации пользователям. Приложение будет состоять из серверной части на Go и клиентской части в виде HTML-страницы.
Сам проект организуем подобным образом:
/project-folder │ ├── main.go # файл сервера Go ├── static # папка для статических файлов │ └── index.html # HTML файл └──
Серверная часть (main.go)
Импорты и структура запроса
import ( "bytes" "encoding/json" "fmt" "html/template" "log" "math/rand" "net/http" "sync" "time" "golang.org/x/time/rate" ) // SMSRequest определяет структуру для данных запроса к SMS API type SMSRequest struct { Number string `json:"number"` // номер отправителя или альфа-имя Destination string `json:"destination"` // номер получателя Text string `json:"text"` // текст сообщения }
Импортируемые пакеты предоставляют функции для работы с HTTP, шаблонами, случайными числами и JSON. SMSRequest — структура для упаковки данных, которые будут отправлены к SMS API.
Главная функция
var ( limiter = rate.NewLimiter(1/120.0, 1) // 1 запрос раз в две 2 минуты mu sync.Mutex ) func main() { http.HandleFunc("/", serveHome) http.HandleFunc("/send", rateLimit(handleSendSMS)) log.Println("Server started on http://localhost:8080") log.Fatal(http.ListenAndServe(":8080", nil)) }
Здесь настроили маршрутизацию. Корневой URL обрабатывается функцией serveHome, а URL /send — функцией handleSendSMS. Также добавили ограничение по запросам.
Запуск сервера на порту 8080.
Функция serveHome
func serveHome(w http.ResponseWriter, r *http.Request) { t, err := template.ParseFiles("static/index.html") if err != nil { http.Error(w, "Internal Server Error", 500) return } t.Execute(w, nil) }
Загружает HTML-шаблон из файла и отображает его. Это входная точка для юзеров.
Функция handleSendSMS
func handleSendSMS(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Redirect(w, r, "/", http.StatusSeeOther) return } err := r.ParseForm() if err != nil { http.Error(w, "Failed to parse form", 400) return } number := r.FormValue("number") code := generateCode(8) message := fmt.Sprintf("Your verification code is: %s", code) if err := sendSMS(number, message); err != nil { log.Printf("Failed to send SMS: %v", err) http.Error(w, "Failed to send SMS", 500) return } fmt.Fprintf(w, "SMS with code sent to %s", number) }
Обрабатывает POST-запросы от формы на HTML-странице, а также генерирует код, формирует сообщение и отправляет SMS.
Функция generateCode
func generateCode(length int) string { var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") rand.Seed(time.Now().UnixNano()) b := make([]rune, length) for i := range b { b[i] = letters[rand.Intn(len(letters))] } return string(b) }
Генерирует случайный код заданной длины.
Функция sendSMS
func sendSMS(destination, message string) error { requestData := SMSRequest{ Number: "ВАШ_НОМЕР", // заменяем на наш купленный номер Destination: destination, Text: message, } jsonData, err := json.Marshal(requestData) if err != nil { return err } req, err := http.NewRequest("POST", "https://api.exolve.ru/messaging/v1/SendSMS", bytes.NewBuffer(jsonData)) if err != nil { return err } req.Header.Set("Authorization", "Bearer ваш_API_ключ") // заменяем на наш API ключ req.Header.Set("Content-Type", "application/json") client := &http.Client{} resp, err := client.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return fmt.Errorf("failed to send SMS: received status code %d", resp.StatusCode) } return nil }
Отправляет SMS через API. Здесь важно не забыть заменить «ВАШ_НОМЕР» и «ваш_API_ключ» на ваши данные.
Функция rateLimit
func rateLimit(next http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { mu.Lock() defer mu.Unlock() if !limiter.Allow() { http.Error(w, "Too Many Requests", http.StatusTooManyRequests) return } next.ServeHTTP(w, r) } }
Функция для защиты от спама.
Клиентская часть (index.html)
HTML-страница предоставляет простую форму для ввода номера телефона, куда будет отправлен код.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Request SMS Code</title> <style> body { font-family: Arial, sans-serif; background-color: #f4f4f9; margin: 0; padding: 20px; display: flex; justify-content: center; align-items: center; height: 100vh; } form { background: white; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); } input[type="text"], button { width: 100%; padding: 10px; margin-top: 10px; border: 2px solid #ddd; border-radius: 4px; box-sizing: border-box; } button { background-color: #0056b3; color: white; border: none; cursor: pointer; } button:disabled { background-color: #888; cursor: not-allowed; } button:hover:enabled { background-color: #004494; } #timer { margin-top: 10px; color: #d9534f; } </style> </head> <body> <form id="smsForm" action="/send" method="post"> <h2>Введите свой номер телефона:</h2> <input type="text" id="number" name="number" placeholder="Phone number" required> <button type="submit" id="sendButton">Send Code</button> <p id="timer"></p> </form> <script> const sendButton = document.getElementById('sendButton'); const timer = document.getElementById('timer'); const form = document.getElementById('smsForm'); let remainingTime = 0; form.addEventListener('submit', function(event) { event.preventDefault(); if (remainingTime > 0) return; sendButton.disabled = true; remainingTime = 120; updateTimer(); setTimeout(() => { form.submit(); }, 1000); const interval = setInterval(() => { remainingTime--; updateTimer(); if (remainingTime <= 0) { clearInterval(interval); sendButton.disabled = false; } }, 1000); }); function updateTimer() { if (remainingTime > 0) { timer.textContent = `Пожалуйста, подождите ${remainingTime} секунд перед отправкой следующего запроса.`; } else { timer.textContent = ''; } } </script> </body> </html>
Постарался более-менее сделать красивую страничку и добавил форму с методом POST по адресу /send для отправки данных на сервер. Пользователю предлагается ввести номер телефона, это обязательное поле, и отправить его нажатием на кнопку.
А теперь запустим все это дело
Переходим в папку проекта: открываем командную строку и переходим в папку, где находится main.go. Это можно сделать с помощью команды cd:
cd C:\Users\user1\projects\project
Запускаем сервер с помощью команды go run для запуска вашего сервера:
go run main.go
Так мы запустили сервер на том порту, который указали в файле main.go и теперь можно подключиться к серверу через браузер, перейдя по адресу http://localhost:8080.
Переходим и видим нашу форму:
Вводим номер телефона, нажимаем Send Code и в консоли видим это сообщение:
После чего на номер приходит SMS:
Все работает отлично! Получили сгенерированный код.
Также важно сказать здесь о том, что тестовый баланс позволяет отправлять SMS только на номер, который вы указали при регистрации.
Что еще можно добавить
Естественно здесь уместно добавить систему логирования. В Go для этого можно использовать стандартный пакет log или более крутые решения вроде logrus или zap.
Можно расширить, добавив более детальную классификацию и обработку различных видов ошибок, возвращаемых API.
В текущем коде API-ключ и номер отправителя зашиты непосредственно в коде. В продакшене рекомендую использовать переменные окружения для хранения чувствительных данных.
Несмотря на то, что HTML-страница выполнена в целом функционально, всегда есть возможность для улучшения визуальной составляющей и пользовательского интерфейса. Можно добавить адаптивность для различных устройств и использовать фреймворки типа React или Vue.js.
Можно также добавить функции по работе с шаблонами сообщений, которые пользователь мог бы выбирать из списка, или интеграция с БД для сохранения истории отправленных сообщений, хотя у самого Exolve есть замечательная вкладка по статистике отправленных сообщений и там их можно просматривать.
В заключение
Благодаря простому API можно легко внедрять функции отправки и приема SMS в любые приложения, улучшать взаимодействие с пользователями, оптимизировать свои коммуникации и получать подробную аналитику и отчеты о результатах кампаний.
ссылка на оригинал статьи https://habr.com/ru/articles/835650/
Добавить комментарий