使用 Rust & Warp 和 Docker 构建安全的 WebSocket 服务器

设置 Rust 项目

让我们开始使用 Cargo 设置 Rust 项目。在这种情况下,要创建我们的新项目

cargo new hello

请将Cargo.toml文件修改为如下所示:

[package]
name = "hello"
version = "0.1.0"
edition = "2022"
[dependencies]
tokio = {version = "1.4.0", features = ["rt", "rt-multi-thread", "macros"]}
warp = {version="*", features = ["tls"]}
futures = "*"

然后,您可以构建项目安装依赖项:

cargo build

从一个简单的 HTTP 服务器开始

  首先,让我们首先使用Warp设置 HTTP 服务器。

index.html当用户请求它时,这将返回一个简单的页面。首先,index.html在与 Rust 项目相同的根目录中创建,然后修改它,如下所示:

<!DOCTYPE html>
<html>
    <body>
        <script>
            window.onload = () => {
                const BACKEND_URL = "wss://" + window.location.hostname + ":9231/echo"
                const socket = new WebSocket(BACKEND_URL)
                socket.onopen = () =>  { 
                    console.log("Socket Opened")
                    setInterval(_ => socket.send("Hello rust!"), 3000)
                }
                socket.onmessage = (msg) => alert(msg.data)
                socket.onerror = (err) => console.error(err)
                socket.onclose = () => console.log("Socket Closed")
            }
        </script>
    </body>
</html>

这设置了一个基本的 WebSocket 客户端,它将发送“Hello rust!” 每 3 秒从客户端的浏览器到我们的 WebSocket 服务器。

接下来,我们需要生成一个公私密钥对,Warp 将使用它来安全地提供内容。在这种情况下,我们可以使用(在项目的根目录中)进行设置:

openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.rsa -out cert.pem

现在,在main.rs文件中,我们可以设置 HTTP 服务器,它将返回我们刚刚创建的上述 HTML,使用简单的 Warp 路由:

use warp::Filter;
#[tokio::main]
async fn main() {    
    let current_dir = std::env::current_dir().expect("failed to read current directory");
    let routes = warp::get().and(warp::fs::dir(current_dir));
warp::serve(routes)
        .tls()
        .cert_path("cert.pem")
        .key_path("key.rsa")
        .run(([0, 0, 0, 0], 9231)).await;
}

现在再次运行:

cargo run

这将在https://0.0.0.0:9231/index.html处显示一个空白页面,并要求您在浏览器上导航到该站点时接受证书警告。

现在页面将尝试连接到我们尚不存在的 WebSocket 服务器。

实现 WebSocket 服务器

然后我们可以设置 WebSocket 服务器,作为 Warp 服务器上的附加路由。您可以将main.rs文件修改为现在如下所示:

use futures::StreamExt;
use futures::FutureExt;
use warp::Filter;
#[tokio::main]
async fn main() {
let echo = warp::path("echo")
        .and(warp::ws())
        .map(|ws: warp::ws::Ws| {
            ws.on_upgrade(|websocket| {
                let (tx, rx) = websocket.split();
                rx.forward(tx).map(|result| {
                    if let Err(e) = result {
                        eprintln!("websocket error: {:?}", e);
                    }
                })
            })
        });
    
    let current_dir = std::env::current_dir().expect("failed to read current directory");
    let routes = warp::get().and(echo.or(warp::fs::dir(current_dir)));
warp::serve(routes)
        .tls()
        .cert_path("cert.pem")
        .key_path("key.rsa")
        .run(([0, 0, 0, 0], 9231)).await;
}

现在创建了一个名为“echo”的路由,上面的实现只是将 WebSocket 上接收到的内容发送回相应的客户端。

现在,如果您使用 运行它cargo run,并导航到与以前相同的站点(https://0.0.0.0:9231/index.html),它将加载 JavaScript(来自index.html 之前创建的),它将尝试连接到echoWebSocket 端点并每 3 秒发送一条消息。

您将能够看到客户端通过alert(...)浏览器内置的机制从服务器接收响应。

注意:这个例子是使用Warp 文档构建的,以及它们的例子的组合——看看基本的 TLS基本的 WebSocket例子。

使用 Docker 构建和运行

  现在我们有一个正在运行的、安全的 HTTP 和 WebSocket 服务器,创建一个容器,我们可以在其中构建和运行我们的应用程序以供以后部署。

首先,在 Rust 项目的根目录中创建一个名为 的文件Dockerfile,并向其中添加以下内容:

#使用最新的Rust官方镜像
FROM rust:latest
#将我们当前的工作目录复制到容器中
COPY ./ ./
#创建发布版本
RUN cargo build --release
#生成我们的自签名证书(相应地更改这些参数!)
RUN openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.rsa -out cert.pem \
    -subj "/C=GB/ST=London/L=London/O=Global Security/OU=IT Department/CN=example.com"
#我们的应用在EXPOSE 9231上运行的端口
EXPOSE 9231
#运行应用程序!
CMD ["./target/release/hello"]

这是一个非常基本的示例,说明我们如何在容器中构建 Rust 应用程序,并在构建过程中生成自签名证书——您需要相应地更改证书信息的参数。

然后我们可以使用以下命令构建和运行容器:

docker build -t hello 。
docker run -p 9231:9231 -t hello

上面将构建一个名为hello的容器,然后运行该容器,并暴露 9231 端口与我们的应用程序通信。

当容器运行时,您可以再次在本地导航到与以前相同的 URL,以访问应用程序并测试它是否正常工作 - https://0.0.0.0:9231/index.html(记住接受自签名证书的风险)。

猜你喜欢

转载自blog.csdn.net/love906897406/article/details/126514570