Как создать генератор кодов верификации на Go с помощью SMS API
Привет, Хабр! Всегда было любопытно, как автоматизировать отправку кодов через SMS для второго этапа подтверждения личности при входе пользователя. Мы с коллегой решили разработать простой, но эффективный инструмент, который мог бы автоматически генерировать и отправлять SMS с кодами пользователя. Для реализации этой задачи выбрали API сервиса МТС Exolve.
Этот сервис упрощает рассылку SMS и предоставляет удобные инструменты для работы с сообщениями. Также Exolve добавляет новым пользователям 300 рублей на счет для тестирования платформы, что в целом достаточно для того, чтобы оценить все функции сервиса без начальных инвестиций.
Как начать работу
Первый шаг для старта работы с Exolve — регистрация на официальном сайте. После неё появится доступ к личному кабинету, где можно управлять настройками и использовать различные функции платформы.
Для начала работы с API, необходимо создать приложение. Это делается во вкладке Приложения в аккаунте. Создание приложения позволит сгенерировать API ключи, необходимые для работы с SMS.
В данном случае мы создали приложение Habr
После создания приложения переходим во вкладку Ключи в настройках приложения, чтобы сгенерировать новый API ключ. Ключ будет использоваться для аутентификации ваших запросов к API Exolve.
Вкладка API-ключей
Для отправки 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-страница предоставляет простую форму для ввода номера телефона, куда будет отправлен код.
Request SMS Code
Постарался более-менее сделать красивую страничку и добавил форму с методом POST по адресу /send для отправки данных на сервер. Пользователю предлагается ввести номер телефона, это обязательное поле, и отправить его нажатием на кнопку.
А теперь запустим все это дело
Переходим в папку проекта: открываем командную строку и переходим в папку, где находится main.go. Это можно сделать с помощью команды cd:
cd C:\Users\user1\projects\project
Запускаем сервер с помощью команды go run для запуска вашего сервера:
go run main.go
Так мы запустили сервер на том порту, который указали в файле main.go и теперь можно подключиться к серверу через браузер, перейдя по адресу http://localhost:8080.
Переходим и видим нашу форму:
Веб-страница по localhost:8080
Вводим номер телефона, нажимаем Send Code и в консоли видим это сообщение:
SMS успешно отправлено
После чего на номер приходит SMS:
SMS
Все работает отлично! Получили сгенерированный код.
Также важно сказать здесь о том, что тестовый баланс позволяет отправлять SMS только на номер, который вы указали при регистрации.
Что еще можно добавить
Естественно здесь уместно добавить систему логирования. В Go для этого можно использовать стандартный пакет log или более крутые решения вроде logrus или zap.
Можно расширить, добавив более детальную классификацию и обработку различных видов ошибок, возвращаемых API.
В текущем коде API-ключ и номер отправителя зашиты непосредственно в коде. В продакшене рекомендую использовать переменные окружения для хранения чувствительных данных.
Несмотря на то, что HTML-страница выполнена в целом функционально, всегда есть возможность для улучшения визуальной составляющей и пользовательского интерфейса. Можно добавить адаптивность для различных устройств и использовать фреймворки типа React или Vue.js.
Можно также добавить функции по работе с шаблонами сообщений, которые пользователь мог бы выбирать из списка, или интеграция с БД для сохранения истории отправленных сообщений, хотя у самого Exolve есть замечательная вкладка по статистике отправленных сообщений и там их можно просматривать.
В заключение
Благодаря простому API можно легко внедрять функции отправки и приема SMS в любые приложения, улучшать взаимодействие с пользователями, оптимизировать свои коммуникации и получать подробную аналитику и отчеты о результатах кампаний.