Форум

Авторизованный вход в SMPP сервер

Всем привет!

Предлагаю вам ознакомится со следующей статьей из серии создания и тюнинга собственного SMPP сервера для приема СМС на платформе Exolve. Уже на протяжении долгого времени сервер работает в открытом доступе, что кажется не так безопасно. Так давайте настроим вход по логину и паролю. Данные для входа вы можете найти в кабинете разработчика dev.exolve.ru

Как это будет работать теперь?

app.py
    1. Инициализация Flask и SQLAlchemy:
  • Flask используется для создания веб-приложения, а SQLAlchemy для работы с базой данных SQLite, где будут храниться SMS-сообщения.
  • Приложение настроено на использование секретного ключа для управления сессиями и хранения состояния авторизации.
2. Модель данных SMSMessage:
  • Создана модель для хранения SMS-сообщений в базе данных. Каждое сообщение содержит информацию об отправителе, получателе, тексте сообщения и времени получения.
3. SMPP Клиент:
  • client - это объект SMPP клиента, который используется для подключения и работы с SMPP сервером. Глобальная переменная connection_status используется для отслеживания состояния подключения.
  • Функция handle_message обрабатывает входящие сообщения и сохраняет их в базе данных.
4. Подключение к SMPP серверу:
  • Функция connect_to_smpp принимает учетные данные (System ID и пароль) и пытается подключиться к SMPP серверу. Если подключение успешно, запускается поток для прослушивания входящих сообщений.
5. Маршруты Flask:
  • / - форма для ввода учетных данных и подключения к SMPP серверу. После успешного подключения пользователь перенаправляется на страницу со списком сообщений.
  • /messages - страница, отображающая полученные SMS-сообщения.
  • /get_messages - маршрут, который возвращает список сообщений в формате JSON для отображения их на странице.
6. Закрытие SMPP клиента:
  • Функция close_smpp_client корректно завершает соединение с SMPP сервером при завершении работы приложения.
index.html

Статус подключения и список сообщений:
  • На странице отображается текущий статус подключения к SMPP серверу и список полученных SMS-сообщений.

  • Сообщения обновляются каждые 5 секунд без необходимости перезагрузки страницы, благодаря JavaScript.

login.html

Форма для подключения:

Пользователь вводит System ID и пароль для подключения к SMPP серверу. После отправки формы происходит подключение, и пользователь перенаправляется на страницу с сообщениями.

Итого получаем
  • Пользователь сначала заходит на страницу с формой (login.html), вводит свои учетные данные и подключается к SMPP серверу.

  • Если подключение успешно, он перенаправляется на страницу (index.html), где отображаются полученные SMS-сообщения.

  • Статус подключения и сообщения обновляются в реальном времени, и сообщения сохраняются в базе данных для последующего просмотра.

А теперь сам код app.py:

Код
import smpplib.clientimport smpplib.constsimport smpplib.gsmimport smpplib.exceptionsfrom flask import Flask, jsonify, render_template, request, redirect, url_for, sessionfrom flask_sqlalchemy import SQLAlchemyimport threadingimport atexit
# Настройки Flask и базы данныхapp = Flask(__name__)app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sms.db'app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = Falseapp.config['SECRET_KEY'] = 'your_secret_key'  # Для безопасности сессийdb = SQLAlchemy(app)
# Модель для хранения SMS сообщенийclass SMSMessage(db.Model):    id = db.Column(db.Integer, primary_key=True)    source = db.Column(db.String(20))    destination = db.Column(db.String(20))    message = db.Column(db.String(160))    timestamp = db.Column(db.DateTime, default=db.func.current_timestamp())
# Создаем таблицы в базе данныхwith app.app_context():    db.create_all()
# Глобальные переменные для состояния SMPP клиентаclient = Noneconnection_status = "Not connected"
# Функция для обработки входящих сообщенийdef handle_message(pdu):    try:        # Попытка декодировать сообщение с разными кодировками        try:            if pdu.data_coding == 0x08:  # UCS2 кодировка                message = pdu.short_message.decode('utf-16-be')            else:                message = pdu.short_message.decode('utf-8')        except UnicodeDecodeError:            # Если не удалось, пробуем GSM 7-бит (возможные латинские символы)            try:                message = smpplib.gsm.decode(pdu.short_message)            except:                # Если ничего не помогло, сохраняем как есть                message = pdu.short_message.decode('latin1')
        source = pdu.source_addr.decode('utf-8') if isinstance(pdu.source_addr, bytes) else pdu.source_addr        destination = pdu.destination_addr.decode('utf-8') if isinstance(pdu.destination_addr, bytes) else pdu.destination_addr
        # Создаем контекст приложения Flask        with app.app_context():            # Сохраняем сообщение в базе данных            sms = SMSMessage(source=source, destination=destination, message=message)            db.session.add(sms)            db.session.commit()
        print(f"Received message: {message}")        print(f"From: {source}")        print(f"To: {destination}")
    except UnicodeDecodeError as e:        print(f"Ошибка декодирования сообщения: {e}")    except smpplib.exceptions.ConnectionError as e:        global connection_status        connection_status = "Connection lost"        print("Connection lost with SMPP server:", e)
# Функция для подключения к SMPP серверуdef connect_to_smpp(system_id, password):    global client, connection_status    SMPP_SERVER = "smpp.exolve.ru"    SMPP_PORT = 2775
    try:        client = smpplib.client.Client(SMPP_SERVER, SMPP_PORT)        client.set_message_received_handler(handle_message)        client.connect()        client.bind_receiver(system_id=system_id, password=password)        connection_status = "Connected"        listener_thread = threading.Thread(target=client.listen, daemon=True)        listener_thread.start()    except Exception as e:        connection_status = f"Failed to connect: {str(e)}"
# Функция для корректного закрытия SMPP клиентаdef close_smpp_client():    global client, connection_status    if client:        try:            client.unbind()        finally:            client.disconnect()        connection_status = "Disconnected"
# Регистрация функции закрытия соединения при завершении работы приложенияatexit.register(close_smpp_client)
# Маршрут для отображения формы логина и обработки подключения@app.route('/', methods=['GET', 'POST'])def login():    if request.method == 'POST':        system_id = request.form['system_id']        password = request.form['password']        connect_to_smpp(system_id, password)        session['logged_in'] = True        return redirect(url_for('index'))    return render_template('login.html', connection_status=connection_status)
# Веб-интерфейс для отображения полученных SMS@app.route('/messages')def index():    if not session.get('logged_in'):        return redirect(url_for('login'))    messages = SMSMessage.query.order_by(SMSMessage.timestamp.desc()).all()    return render_template('index.html', messages=messages, connection_status=connection_status)
# Маршрут для получения сообщений в формате JSON@app.route('/get_messages', methods=['GET'])def get_messages():    if not session.get('logged_in'):        return jsonify([])    messages = SMSMessage.query.order_by(SMSMessage.timestamp.desc()).all()    messages_data = []    for sms in messages:        messages_data.append({            "source": sms.source.decode('utf-8') if isinstance(sms.source, bytes) else sms.source,            "destination": sms.destination.decode('utf-8') if isinstance(sms.destination, bytes) else sms.destination,            "message": sms.message,            "timestamp": sms.timestamp.strftime('%Y-%m-%d %H:%M:%S')        })    return jsonify(messages_data)
# Запуск веб-приложения на порту 5001if __name__ == '__main__':    app.run(debug=True, port=5001)

А теперь фронт на index.htm
Код
<!DO CTYPE html><ht ml lang="ru"><head>    <met a charset="UTF-8">    <met a name="viewport" content="width=device-width, initial-scale=1.0">    <title>Полученные SMS сообщения</title>    <st yle>        .message-text {            color: green;            font-weight: bold;        }        .status {            margin-bottom: 20px;            font-weight: bold;        }    </style>    <sc ript>        // Функция для загрузки сообщений        function loadMessages() {            fetch('/get_messages')                .then(response => response.json())                .then(data => {                    const messageList = document.getElementById('message-list');                    messageList.innerHTML = '';  // Очищаем список сообщений                    data.forEach(sms => {                        const listItem = document.createElement('li');                        listItem.innerHTML = `<span class="message-text">${sms.message}</span> <strong>От:</strong> ${sms.source} <strong>Кому:</strong> ${sms.destination} <strong>Получено в:</strong> ${sms.timestamp}`;                        messageList.appendChild(listItem);                    });                })                .catch(error => console.error('Error loading messages:', error));        }
        // Обновляем сообщения каждые 5 секунд        setInterval(loadMessages, 5000);
        // Загрузка сообщений при загрузке страницы        window.onl oad = loadMessages;    </sc ript></head><body>    <h1>Полученные SMS сообщения</h1>    <div class="status">        Статус подключения: {{ connection_status }}    </div>    <h2>Сообщения</h2>    <ul id="message-list">        <!-- Сообщения будут динамически добавляться сюда -->    </ul></body></html>

И наконец форма входа login.html
Код
<!DO CTYPE html><ht ml lang="ru"><head>    <met a charset="UTF-8">    <met a name="viewport" content="width=device-width, initial-scale=1.0">    <title>Подключение к SMPP серверу</title>    <st yle>        .form-container {            margin: 0 auto;            max-width: 300px;            padding: 20px;            border: 1px solid #ccc;            border-radius: 5px;        }        .form-container h1 {            text-align: center;        }        .form-container label {            display: block;            margin-bottom: 10px;        }        .form-container input {            width: 100%;            padding: 8px;            margin-bottom: 20px;        }        .form-container button {            width: 100%;            padding: 10px;            background-color: #4CAF50;            color: white;            border: none;            border-radius: 5px;            cursor: pointer;        }        .form-container button:hover {            background-color: #45a049;        }        .status {            margin-bottom: 20px;            font-weight: bold;            text-align: center;        }    </style></head><body>    <div class="form-container">        <h1>Подключение к SMPP серверу</h1>        <div class="status">            Статус подключения: {{ connection_status }}        </div>        <fo rm method="POST" action="/">            <label for="system_id">System ID:</label>            <input type="text" id="system_id" name="system_id" required>
            <label for="password">Пароль:</label>            <input type="password" id="password" name="password" required>
            <button type="submit">Подключиться</button>        </form>    </div></body></html>

Тут кстати стоит уделить внимание структуре файлов, наверное в предыдущих публикациях не писал.

Сперва создаем папку для приложения smpp_priem, внутри создаем файл app.py куда пишем код выше. В этой же папке нужно создать новую папку с названием templates, внутри которого должны находится файлы index.html и login.html.

Для запуска используем python app.py находясь в вышеуказанной папке. И чтобы увидеть веб интерфейс, заходим localhost:5001

На этом сегодня все. Надеюсь было интересно и кто нибудь уже повторил проект.

1
164
Открытая тема
0 баллов

Для того, чтобы оставлять комментарии, необходимо пройти авторизацию

Авторизоваться
непонятно куда что вставлять в папках
oleg
oleg
0 баллов
14 дней назад в 04:35