python websockets ssl with Let's Encrypt
#网络开发人员 #python #websockets #ssl

本教程是对我的要点Python Websockets SSL with Let's Encrypt
的解释。

随着2008年HTML5的推出,该技术立即开始流行。根据W3C的说法,Websocket的基本定义是 - 一个接口,该接口使Web应用程序能够通过服务器端进程维护双向通信。

在本简短的教程中,我将向您展示如何在其上启用使用SSL的Websocket服务器。这允许您的插座服务器在HTTPS地址上运行。

设置

我们将使用asyncio库,用于WebSocket服务器实现将使用websockets库。

自Python 3.4以来,asyncio库预先包含Python发行版。要安装websockets库,您可以使用以下命令:

pip install websockets

接下来,我们将研究如何生成SSL证书文件。

使用让我们加密生成证书和密钥文件

在可以通过Python脚本运行的Websocket上启用SSL之前,您必须为域生成证书文件。

此步骤的基本要旨是获取让您的域签名认证,并将其存储在服务器上的Python Websocket正在运行的位置。

这是关于How To Use Certbot Standalone Mode to Retrieve Let's Encrypt SSL Certificates on Ubuntu 20.04的绝佳快速教程。

使证书文件可访问

正确生成文件后,您需要使运行Python WebSocket脚本的当前用户可以访问它们。

在上一步中,如果certbot将证书文件存储在/etc/letsencrypt/live/your_domain位置,则在文件夹上执行ls时应该可以看到4个文件 -

~$ ls /etc/letsencrypt/live/your_domain
cert.pem  chain.pem  fullchain.pem  privkey.pem  README

要更改证书文件的所有者,请使用以下命令:

~$ sudo chown -R $(id -u):$(id -g) /etc/letsencrypt/live/your_domain

接下来,确保将正确的权限应用于文件夹:

~$ sudo chmod -R 400 /etc/letsencrypt/live/your_domain

我们现在很高兴从Python WebSocket脚本读取这些文件。

创建服务器脚本

虽然您的WebSocket Server脚本与大多数Barebones的实现有所不同,但这是您的一个适合您 -

创建一个名为socket_server.py的文件。然后,进行所有必要的进口。

#!/usr/bin/env python

# WS server example that synchronizes state across clients

import asyncio
import json
import logging
import websockets
import ssl

logging.basicConfig()

接下来,让我们为此脚本配置SSL,如下所示 -

ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)

# Generate with Lets Encrypt, chown to current user and 400 permissions
ssl_cert = "/etc/letsencrypt/live/your_domain/fullchain.pem"
ssl_key = "/etc/letsencrypt/live/your_domain/privkey.pem"

ssl_context.load_cert_chain(ssl_cert, keyfile=ssl_key)

上面的代码将脚本配置为运行TLS服务器,并在certbot生成的文件夹中可用的证书。

接下来,我们定义用于通知客户端服务器并从中获取信息的功能。

STATE = {"value": 0}

USERS = set()


def state_event():
    return json.dumps({"type": "state", **STATE})


def users_event():
    return json.dumps({"type": "users", "count": len(USERS)})


async def notify_state():
    if USERS:  # asyncio.wait doesn't accept an empty list
        message = state_event()
        await asyncio.wait([user.send(message) for user in USERS])


async def notify_users():
    if USERS:  # asyncio.wait doesn't accept an empty list
        message = users_event()
        await asyncio.wait([user.send(message) for user in USERS])

之后,我们需要添加从Websocket注册和注册客户端的函数。

async def register(websocket):
    USERS.add(websocket)
    await notify_users()


async def unregister(websocket):
    USERS.remove(websocket)
    await notify_users()

这样做,让我们实现一个函数,该函数从客户端获取状态更新请求并执行。

async def counter(websocket, path):
    # register(websocket) sends user_event() to websocket
    await register(websocket)
    try:
        await websocket.send(state_event())
        async for message in websocket:
            data = json.loads(message)
            if data["action"] == "minus":
                STATE["value"] -= 1
                await notify_state()
            elif data["action"] == "plus":
                STATE["value"] += 1
                await notify_state()
            else:
                logging.error("unsupported event: {}", data)
    finally:
        await unregister(websocket)

最后,我们运行服务器。

start_server = websockets.serve(counter, "0.0.0.0", 6789, ssl=ssl_context)

asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

您如何将服务器公开到Internet,我将将其放在您的用例上。但是,您可以在Websockets - Deploy behind nginx上探索本教程。

实施客户页面

要测试上述WebSocket脚本,您可以旋转自己的客户端脚本或随时使用我提供的socket_client.html文件。

确保更新客户端文件中的以下行以指向您的实时服务器 -

websocket = new WebSocket("wss://localhost:6789/");

请注意,我们在此处使用wss://协议,而不是ws://协议,该协议通常在Internet上的其他教程中找到。

结论

这是我尝试解释一年多以前提出的要点的尝试。希望它可以帮助您比我首先写的过程更容易完成整个过程。

确保给我关于此博客的反馈!