Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OTP Service – Сервис одноразовых кодов подтверждения

Backend-приложение для безопасного подтверждения операций с помощью временных кодов (OTP), отправляемых через Telegram. Проект выполнен в рамках учебного кейса от компании Promo IT.

📌 Оглавление


Возможности

- Регистрация и аутентификация пользователей (JWT-токены).
- Автоматическое назначение роли `ADMIN` первому зарегистрированному пользователю.
- Генерация OTP-кода заданной длины и времени жизни.
- Отправка кода через Telegram (эмуляция SMS и Email не реализована).
- Валидация OTP с проверкой срока действия и статуса.
- Фоновый процесс автоматической прострочки кодов (статус `EXPIRED`).
- API администратора: просмотр и удаление обычных пользователей, изменение параметров OTP.
- Хранение данных в PostgreSQL 17, работа через JDBC.
- Логирование с помощью SLF4J + Logback.
- Сборка с Maven, упаковка в исполняемый JAR.

Технологии

| Компонент        | Технология               |
|------------------|--------------------------|
| Язык             | Java 17                  |
| Сборщик          | Maven                    |
| HTTP-сервер      | `com.sun.net.httpserver` |
| База данных      | PostgreSQL 17            |
| Доступ к БД      | JDBC (чистый SQL)        |
| Аутентификация   | JWT (io.jsonwebtoken)    |
| Хеширование      | BCrypt (jBCrypt)         |
| JSON             | Jackson                  |
| Логирование      | SLF4J + Logback          |
| Уведомления      | Telegram Bot API         |

Требования

- **Java 17** или выше.
- **Maven 3.6+**.
- **PostgreSQL 17** (должен быть запущен локально на порту `5432`).
- **Токен Telegram-бота** и **Chat ID** (для отправки сообщений).

Установка и настройка

1. Клонирование репозитория

git clone https://github.com/lavren007/otp-service.git
cd otp-service

2. Настройка базы данных PostgreSQL

Убедитесь, что PostgreSQL запущен, и у вас есть пользователь postgres с паролем postgres (либо измените параметры подключения в файле DatabaseConnection.java).

При первом запуске приложение автоматически создаст базу данных otp_db и все необходимые таблицы.
Если хотите создать БД вручную:

CREATE DATABASE otp_db;

Параметры подключения по умолчанию (можно изменить в DatabaseConnection.java):

private static final String URL = "jdbc:postgresql://localhost:5432/otp_db";
private static final String USER = "postgres";
private static final String PASSWORD = "postgres";

3. Создание Telegram-бота

1. Откройте Telegram и найдите [@BotFather](https://t.me/botfather).
2. Отправьте команду `/newbot` и следуйте инструкциям.
3. После создания вы получите **токен** бота (например, `1234567890:ABCdefGHIjklMNOpqrsTUVwxyz`).
4. Найдите своего бота в Telegram по username и отправьте ему любое сообщение (например, "Привет").
5. Получите ваш **Chat ID**, перейдя по ссылке:

https://api.telegram.org/bot<ВАШ_ТОКЕН>/getUpdates

В ответе найдите поле `chat` → `id`.  
Пример:
```json
"chat": {
    "id": 123456789,
    ...
}

Запомните это число (может быть отрицательным для групповых чатов).

4. Установка переменных окружения

Перед запуском приложения необходимо задать две переменные окружения:

  • TELEGRAM_BOT_TOKEN – токен вашего бота.
  • TELEGRAM_CHAT_ID – ваш Chat ID.
TELEGRAM_BOT_TOKEN=ваш_токен_бота
TELEGRAM_CHAT_ID=ваш_chat_id

Windows (cmd):

set TELEGRAM_BOT_TOKEN=ваш_токен_бота
set TELEGRAM_CHAT_ID=ваш_chat_id

Linux / macOS:

export TELEGRAM_BOT_TOKEN="ваш_токен_бота"
export TELEGRAM_CHAT_ID="ваш_chat_id"

⚠️ Если переменные не заданы, приложение запустится, но отправка кодов в Telegram будет невозможна (в логах появится предупреждение).


Сборка и запуск

Сборка исполняемого JAR

mvn clean package

После успешной сборки в папке target/ появится файл otp-service-1.0.0.jar.

Запуск (с переменными окружения)

TELEGRAM_BOT_TOKEN="ваш_токен_бот" \
TELEGRAM_CHAT_ID="ваш_chat_id" \
java -jar target/otp-service-1.0.0.jar

После запуска вы увидите в консоли сообщение:

Server started on port 8080
API endpoints available at http://localhost:8080

Сервер будет слушать порт 8080. Чтобы изменить порт, отредактируйте SERVER_PORT в классе AppConfig.


API-эндпоинты

Все эндпоинты (кроме /api/auth/*) требуют передачи JWT-токена в заголовке:

Authorization: Bearer <ваш_токен>

Формат данных – JSON.


Аутентификация

Регистрация

Создаёт нового пользователя.
Первый зарегистрированный пользователь автоматически получает роль ADMIN.
Все последующие – роль USER.

Запрос (macOS / Linux):

curl -X POST http://localhost:8080/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin123"}'

Запрос (Windows cmd):

curl -X POST http://localhost:8080/api/auth/register -H "Content-Type: application/json" -d "{\"username\":\"admin\",\"password\":\"admin123\"}"

Ответ (200 OK):

{
  "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsInJvbGUiOiJBRE1JTiIsImlhdCI6MTYxMDAwMDAwMCwiZXhwIjoxNjEwMDAzNjAwfQ.abc123..."
}

Ошибки:

  • 400 Bad Request – имя пользователя уже занято или не переданы поля.

Вход

Аутентифицирует пользователя и возвращает JWT-токен.

Запрос (macOS / Linux):

curl -X POST http://localhost:8080/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin123"}'

Ответ (200 OK):

{
  "token": "eyJhbGciOiJIUzI1NiJ9..."
}

Ошибки:

  • 401 Unauthorized – неверное имя пользователя или пароль.

Пользовательские методы

Требуют валидный JWT-токен (роль может быть любой).

Генерация OTP

Генерирует уникальный operationId и OTP-код, отправляет код через Telegram, а также сохраняет его в файл otp_codes.txt в корне проекта.

Запрос (macOS / Linux):

curl -X POST http://localhost:8080/api/user/otp/generate \
  -H "Authorization: Bearer <токен>"

Ответ (200 OK):

{
  "operationId": "550e8400-e29b-41d4-a716-446655440000",
  "message": "OTP sent via Telegram and saved to file"
}

В Telegram-бот придёт сообщение вида:

Your OTP code is: 483201

Проверка OTP

Проверяет правильность кода для указанной операции. При успехе переводит код в статус USED.

Запрос (macOS / Linux):

curl -X POST http://localhost:8080/api/user/otp/validate \
  -H "Authorization: Bearer <токен>" \
  -H "Content-Type: application/json" \
  -d '{"operationId":"550e8400-e29b-41d4-a716-446655440000","code":"483201"}'

Ответ (200 OK):

{
  "valid": true
}

Если код неверен / просрочен / уже использован:

{
  "valid": false
}

Административные методы

Доступны только пользователям с ролью ADMIN.
Требуют JWT-токен администратора.

Получение списка пользователей

Возвращает всех пользователей, кроме администраторов.

Запрос (macOS / Linux):

curl -X GET http://localhost:8080/api/admin/users \
  -H "Authorization: Bearer <админский_токен>"

Ответ (200 OK):

[
  {
    "id": 2,
    "username": "user1",
    "passwordHash": "$2a$10$...",
    "role": "USER"
  },
  {
    "id": 3,
    "username": "user2",
    "passwordHash": "$2a$10$...",
    "role": "USER"
  }
]

Удаление пользователя

Удаляет пользователя с указанным ID и все его OTP-коды. Нельзя удалить администратора.

Запрос (macOS / Linux):

curl -X DELETE http://localhost:8080/api/admin/users/2 \
  -H "Authorization: Bearer <админский_токен>"

Ответ (200 OK):

{
  "message": "User deleted"
}

Ошибки:

  • 404 Not Found – пользователь с таким ID не найден.
  • 400 Bad Request – попытка удалить администратора.

Изменение конфигурации OTP

Позволяет изменить длину генерируемого кода и время его жизни (в секундах).

Запрос (macOS / Linux):

curl -X PUT http://localhost:8080/api/admin/config \
  -H "Authorization: Bearer <админский_токен>" \
  -H "Content-Type: application/json" \
  -d '{"codeLength":8,"ttlSeconds":600}'

Ответ (200 OK):

{
  "message": "Config updated"
}

Параметры:

Поле Тип Описание
codeLength int Количество цифр в коде (≥ 4)
ttlSeconds int Время жизни кода в секундах (≥ 1)

Структура проекта

src/main/java/com/example/otpservice/
├── Main.java                     # Точка входа, инициализация БД и сервера
├── config/
│   └── AppConfig.java            # Константы приложения (порт)
├── controller/                   # Обработчики HTTP-запросов
│   ├── BaseHandler.java
│   ├── AuthController.java
│   ├── UserController.java
│   └── AdminController.java
├── service/                      # Бизнес-логика
│   ├── AuthService.java
│   ├── OtpService.java
│   ├── UserService.java
│   ├── NotificationService.java
│   └── ExpiredOtpCleanupService.java
├── dao/                          # Доступ к базе данных (JDBC)
│   ├── DatabaseConnection.java
│   ├── UserDao.java
│   ├── OtpConfigDao.java
│   └── OtpCodeDao.java
├── model/                        # Сущности
│   ├── User.java
│   ├── OtpConfig.java
│   ├── OtpCode.java
│   ├── Role.java
│   └── OtpStatus.java
├── util/                         # Вспомогательные классы
│   ├── JwtUtil.java
│   ├── PasswordUtil.java
│   ├── OtpGenerator.java
│   ├── JsonUtil.java
│   └── TelegramNotifier.java
└── middleware/                   # Фильтры HTTP
    ├── AuthFilter.java
    └── LoggingFilter.java        # Логирование всех запросов

Тестирование

Для тестирования API вы можете использовать:

  • cURL (командная строка) – примеры приведены выше.
  • Postman – удобный графический HTTP-клиент.
  • Insomnia – легковесная альтернатива Postman.
  • HTTP-клиент в IDE (IntelliJ IDEA Ultimate, VS Code с REST Client).

Простой сценарий проверки:

  1. Зарегистрируйте первого пользователя (станет администратором).
  2. Войдите, чтобы получить токен.
  3. Сгенерируйте OTP (проверьте Telegram и файл otp_codes.txt).
  4. Введите полученный код для валидации – должно вернуться {"valid":true}.
  5. Попробуйте повторно использовать тот же код – должно быть false.
  6. Подождите истечения TTL (по умолчанию 300 секунд) и повторите валидацию – код станет EXPIRED.

Логирование

В проекте реализовано два уровня логирования:

  1. Логирование всех входящих HTTP-запросов (через LoggingFilter): метод, URI, статус ответа, время обработки.
  2. Логирование ключевых событий в сервисах (регистрация, вход, генерация/валидация OTP, ошибки).

Логи выводятся в консоль. Формат и уровень можно настроить в src/main/resources/logback.xml.


Возможные проблемы и их решение

1. Ошибка подключения к PostgreSQL

Симптом: При запуске приложение падает с ошибкой Connection refused.

Решение:

  • Убедитесь, что PostgreSQL запущен (sudo systemctl status postgresql на Linux или brew services list | grep postgresql на macOS).
  • Проверьте параметры подключения в DatabaseConnection.java (порт, пользователь, пароль).
  • Попробуйте подключиться вручную: psql -U postgres -h localhost.

2. Telegram-бот не отправляет сообщения

Симптом: OTP генерируется, но сообщение в Telegram не приходит.

Решение:

  • Проверьте, что переменные окружения TELEGRAM_BOT_TOKEN и TELEGRAM_CHAT_ID заданы и видны процессу Java.
  • Убедитесь, что вы отправили боту хотя бы одно сообщение перед запуском приложения (для активации чата).
  • Проверьте логи приложения – там будут сообщения об ошибках при отправке в Telegram.

3. Порт 8080 уже занят

Симптом: java.net.BindException: Address already in use.

Решение:

  • Остановите предыдущий экземпляр приложения (Ctrl+C в терминале, где он запущен).
  • Или измените порт в AppConfig.java.

Разработчик: [Лаврентьев Антон]
Контакты: [email: anton_lavren@mail.ru]

About

Backend-приложение для безопасного подтверждения операций с помощью временных кодов (OTP), отправляемых через Telegram.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages