Ограничение доступа к командам ТГ-бота?

Отличный вопрос! Ограничение доступа к командам Telegram-бота — это критически важный аспект безопасности и функциональности. В контексте Java-разработки это реализуется с помощью нескольких ключевых подходов.

Рассмотрим подробно методы, лучшие практики и примеры кода.

1. Концепция "Белого списка" (Whitelist) пользователей

Самый простой и надежный способ — разрешить использование бота только определенным пользователям.

Как это работает: Вы заранее сохраняете chatId или userId авторизованных пользователей (например, в базе данных, файле конфигурации или в коде). При получении любого сообщения/команды бот проверяет, есть ли отправитель в этом списке.

Где хранить ID:

  • База данных (Предпочтительно): PostgreSQL, MySQL, H2. Легко управлять списком.
  • Файл конфигурации: config.properties, application.yml (если используете Spring Boot). Удобно для небольшого числа статических пользователей.
  • Переменные окружения: Хорошо для хранения ID администратора.

Пример реализации на Java с использованием библиотеки TelegramBots:

import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;

import java.util.Arrays;
import java.util.List;

public class SecureBot extends TelegramLongPollingBot {

    // Белый список разрешенных chatId (на практике лучше вынести в БД)
    private final List<Long> allowedChatIds = Arrays.asList(
        123456789L, // Ваш chatId
        987654321L  // ChatId другого пользователя
    );

    @Override
    public void onUpdateReceived(Update update) {
        // Проверяем, что update содержит сообщение и от кого оно
        if (update.hasMessage() && update.getMessage().hasText()) {
            Message message = update.getMessage();
            Long chatId = message.getChatId();
            String text = message.getText();

            // Проверка доступа!
            if (!allowedChatIds.contains(chatId)) {
                sendAccessDeniedMessage(chatId);
                return; // Завершаем обработку, если доступ запрещен
            }

            // Если пользователь авторизован, обрабатываем команды как обычно
            handleCommand(chatId, text);
        }
    }

    private void handleCommand(Long chatId, String command) {
        try {
            switch (command) {
                case "/start":
                    execute(SendMessage.builder()
                            .chatId(chatId.toString())
                            .text("Добро пожаловать, у вас есть доступ!")
                            .build());
                    break;
                case "/secret":
                    execute(SendMessage.builder()
                            .chatId(chatId.toString())
                            .text("Это секретная команда!")
                            .build());
                    break;
                // ... другие команды
            }
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }
    }

    private void sendAccessDeniedMessage(Long chatId) {
        try {
            execute(SendMessage.builder()
                    .chatId(chatId.toString())
                    .text("Извините, у вас нет доступа к этому боту.")
                    .build());
        } catch (TelegramApiException e) {
            e.printStackTrace();
        }
    }

    @Override
    public String getBotUsername() {
        return "YourSecureBot";
    }

    @Override
    public String getBotToken() {
        return "your-bot-token";
    }
}

---

2. Система ролей и прав (Role-Based Access Control - RBAC)

Это более продвинутый подход, который позволяет гибко управлять доступом. Пользователям назначаются роли (например, USER, ADMIN, MODERATOR), и каждая команда требует для выполнения определенную роль.

Компоненты системы:

  1. База данных: Таблицы users, roles, user_roles.
  2. Кэширование: Чтобы не обращаться к БД при каждом сообщении, можно кэшировать роли пользователя (например, используя Caffeine или Redis).

Пример упрощенной реализации:

// Сервис для проверки прав
@Service
public class AuthorizationService {

    @Autowired
    private UserRepository userRepository; // Ваш репозиторий для работы с БД

    public boolean hasAccess(Long userId, String requiredRole) {
        User user = userRepository.findByUserIdWithRoles(userId); // Метод, который достает пользователя и его роли
        return user != null && user.getRoles().stream()
                .anyMatch(role -> role.getName().equals(requiredRole));
    }
}

// Модифицированный обработчик в боте
@Component
public class RBACBot extends TelegramLongPollingBot {

    @Autowired
    private AuthorizationService authService;

    @Override
    public void onUpdateReceived(Update update) {
        // ... получение chatId, userId, text ...

        // Для команд администрирования проверяем роль
        if (text.startsWith("/admin")) {
            if (!authService.hasAccess(userId, "ADMIN")) {
                sendMessage(chatId, "Недостаточно прав для выполнения этой команды.");
                return;
            }
            handleAdminCommand(chatId, text);
        } else {
            // Обычные команды для всех авторизованных пользователей
            handleUserCommand(chatId, text);
        }
    }

    // ... остальные методы ...
}

---

3. Динамическое управление доступом через админ-команды

Вы можете добавить команды, которые позволяют администраторам управлять доступом прямо из Telegram.

Пример команд:

  • /adduser @username — Добавить пользователя в белый список.
  • /removeuser @username — Удалить пользователя.
  • /listusers — Показать список пользователей с доступом.

Это требует персистентного хранилища (БД) и реализации логики обработки этих команд.

---

4. Использование Webhook и Middleware (для продвинутых фреймворков)

Если вы используете фреймворк вроде Spring Boot вместе с вебхуками, вы можете реализовать механизм проверки доступа на уровне Interceptor'а или Filter'а, прежде чем запрос попадет в контроллер, обрабатывающий команды.

Пример с Spring Boot и фильтром:

@Component
public class TelegramAuthFilter implements Filter {

    @Autowired
    private UserService userService;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;

        // Предположим, что chatId передается в заголовке (нужно настроить бота соответствующим образом)
        String chatIdHeader = httpRequest.getHeader("X-Telegram-Chat-Id");
        if (chatIdHeader == null) {
            // Обработка ошибки: запрос не от Telegram или неправильно сконфигурирован
            ((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN);
            return;
        }

        Long chatId = Long.parseLong(chatIdHeader);
        if (!userService.isUserAllowed(chatId)) {
            // Пользователь не авторизован
            ((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN);
            return;
        }

        // Пользователь авторизован, пропускаем запрос дальше
        chain.doFilter(request, response);
    }
}

---

5. Пароли или кодовые слова для активации доступа

Этот метод полезен, если вы хотите дать доступ тем, кто знает секретную фразу.

Логика:

  1. Пользователь пишет боту кодовое слово (например, /start secret_password_123).
  2. Бот проверяет пароль.
  3. Если пароль верный, chatId пользователя добавляется в базу данных авторизованных пользователей.
  4. Теперь пользователь может использовать все команды.

Резюме и лучшие практики

  1. Никогда не доверяйте клиенту. Все проверки должны выполняться на стороне сервера (вашего бота).
  2. Используйте "Белый список". Это самый безопасный подход. Запретите все по умолчанию и разрешайте только явно указанным пользователям.
  3. Храните данные в БД. Для чего-то большего, чем бот для себя и двух друзей, используйте базу данных. Это удобно для управления и масштабирования.
  4. Не храните конфиденциальные данные в коде. chatId и токены лучше выносить в переменные окружения или файлы конфигурации.
  5. Логируйте попытки доступа. Записывайте в лог все попытки выполнения команд, особенно неудачные. Это поможет выявить подозрительную активность.
  6. RBAC для сложных ботов. Если у бота много пользователей и команд с разным уровнем доступа, инвестируйте время в создание системы ролей.

Выбор конкретного метода зависит от сложности вашего бота и требований к безопасности. Для личного использования часто достаточно простого белого списка, в то время как для публичного или корпоративного бота необходима система RBAC.