閱讀英文

共用方式為

将 Web PubSub 服务与 Azure 应用程序网关配合使用

Azure 应用程序网关是一个在应用程序级别工作的 Web 流量负载均衡器。 它可以用作 Web 客户端的单一联络点,并可配置为根据 HTTP 属性(例如 URI 路径等)将 Web 流量路由到各个后端。 应用程序网关原生支持 WebSocket - 用户无需进行任何特殊配置即可启用 WebSocket。

本指南演示如何使用 Azure 应用程序网关来保护 Web PubSub 资源。 我们通过仅允许来自应用程序网关的流量并禁用到 Web PubSub 资源的公共流量,来实现更高级别的安全性。

如图所示,你需要为 Web PubSub 资源设置一个专用终结点。 此专用终结点需与应用程序网关位于同一虚拟网络中。

该图显示将 Web PubSub 与 Azure 应用程序网关配合使用的体系结构概述。

本指南采用循序渐进的方法。 首先,我们配置应用程序网关,以便可以成功将流量中转到 Web PubSub 资源。 其次,我们应用 Web PubSub 的访问控制功能,以仅允许来自应用程序网关的流量。

步骤 1:配置应用程序网关以将流量中转到 Web PubSub 资源

该图演示了我们在步骤 1 中要实现的目标。

该图显示步骤 1 的体系结构概述:配置应用程序网关以将流量中转到 Web PubSub 资源。

创建 Azure 应用程序网关实例

在 Azure 门户上,搜索“Azure 应用程序网关”并按照步骤创建资源。 示意图中突出显示了关键步骤。

该屏幕截图显示如何创建应用程序网关资源 - 基本信息。

Azure 资源需要虚拟网络才能相互安全通信。 Azure 应用程序网关需要一个专用子网,即我们创建的子网。 在本指南的步骤 1 中,Azure 应用程序网关资源通过公共 Internet 将流量转发到 Web PubSub 资源。 在步骤 2 中,我们创建另一个包含 Web PubSub 资源的子网,以便 Azure 应用程序网关通过虚拟网络安全地将流量转发到 Web PubSub 资源。

配置 Azure 应用程序网关

配置 Azure 应用程序网关需要三个组件。

  • 前端
  • 后端
  • 路由规则

前端是 Azure 应用程序网关的 IP 地址。 由于我们使用 Azure 应用程序网关作为 Web 客户端的单一联络点,因此我们需要为其创建一个公共 IP。

该屏幕截图显示如何创建应用程序网关资源 - 创建公共 IP。

后端是应用程序网关资源可以向其发送流量的资源。 在本示例中,我们有一个目标,即 Web PubSub 资源。 在 Azure 门户上,找到你要在本指南中使用的现有 Web PubSub 资源的主机名。 它应如下所示:xxxx.webpubsub.azure.com

该屏幕截图显示如何创建应用程序网关资源 - 创建后端池。

设置前端和后端之后,需要配置连接前端和后端的路由规则。 路由规则告知应用程序网关如何路由流量以及路由到何处。

首先,我们设置一个侦听器。 此配置告知应用程序网关在端口 80 上侦听 HTTP 流量。

该屏幕截图显示如何创建应用程序网关资源 - 创建路由规则、侦听器。

其次,我们设置后端目标。 我们将后端目标配置为之前创建的后端池,即 Web PubSub 资源。 此外,还需要指定应用程序网关如何转发流量。 可以通过后端设置实现此目的

该屏幕截图显示如何创建应用程序网关资源 - 创建路由规则、后端目标。

Web PubSub 服务仅接受 HTTPs 流量。 因此我们指示应用程序网关使用 HTTPs 来与 Web PubSub 通信。 为了使本指南突出重点,我们让应用程序网关选取主机。 建议的做法是在生产环境中设置自定义域。

该屏幕截图显示如何创建应用程序网关资源 - 创建路由规则、后端设置。

配置完这三个组件后,你应会看到类似于屏幕截图的内容。 可以直观查看流量在应用程序网关中的流动方式:

  1. Web 客户端向应用程序网关资源的公共 IP 发送请求。
  2. 应用程序网关通过查阅用户配置的路由规则来路由流量。
  3. 当路由规则匹配时,流量会定向到指定的后端目标。

该屏幕截图显示如何创建应用程序网关资源 - 已完成。

值得强调的一点是,可以完全相同的方式配置非 WebSocket 连接。 可以详细了解应用程序网关对中转 WebSocket 连接的原生支持

测试并验证应用程序网关是否已正确配置

验证 Web PubSub 资源是否正常

向 Web PubSub 资源的无效终结点发送请求并等待来自 Web PubSub 的错误消息。

curl https://<your-web-pubsub-resource-endpoint>/client

应会看到错误消息“‘hub’值无效”。此错误表明 Web PubSub 服务成功收到请求并做出了相应的响应。

验证应用程序网关是否将流量中转到 Web PubSub 资源

重复类似的步骤并等待相同的错误消息。

curl http://<public-ip-of-your-application-gateway-resource>/client

应会看到相同的错误消息“‘hub’值无效”。此错误表明应用程序网关资源使用配置的路由规则成功路由了流量。

测试并验证应用程序网关是否可以中转 WebSocket 连接

通过 Web PubSub 发布消息

我们创建一个简单的程序来模拟服务器定期通过 Web PubSub 发布消息。 在步骤 1 中,我们在本地运行该程序以验证是否一切正常;在步骤 2 中,将同一应用部署到 Azure 应用服务。

创建文件夹结构
mkdir server && cd server
touch package.json && touch publish.js
复制源代码

将代码复制到创建的 package.json 文件中。

{
  "scripts": {
    "start": "node ./publish.js"
  },
  "dependencies": {
    "@azure/web-pubsub": "^1.1.1",
    "express": "^4.19.2"
  }
}

将代码复制到创建的 publish.js 文件中。

const express = require("express")
// Uses the service SDK, which makes it easy to consume the capabilities of the service
const { WebPubSubServiceClient } = require('@azure/web-pubsub');

const app = express()
const PORT = 3000

// Hardcodes the hub name 
const hub = "myHub1";

// Grabs the connection string stored as an environment variable
let webpubsub = new WebPubSubServiceClient(process.env.WebPubSubConnectionString, hub);

// Serves the files found in the "public" directory  
app.use(express.static("public"))

// Returns Web PubSub's access token
app.get("/negotiate", async (req, res) => {
  let token = await webpubsub.getClientAccessToken()
  let url = token.url
  res.json({
    url
  })
}
// Every 2 seconds, we ask Web PubSub service to send all connected clients the messsage "hello, world"
setInterval(() => {
  webpubsub.sendToAll("hello, world", { contentType: "text/plain" });
}, 2000);

// Starts the server
app.listen(process.env.PORT || PORT, () => console.log(`server running on ${PORT}`));
安装依赖项并运行程序

在 Azure 门户上,找到 Web PubSub 资源的 connection string该屏幕截图显示如何获取 Web PubSub 资源的连接字符串。

npm install

## Set environment variable
export WebPubSubConnectionString="<replace with the connection string of your Web PubSub resource>"

npm run start

控制台中应会显示“服务器在端口 3000 上运行”。 每隔 2 秒,该程序就会要求 Web PubSub 服务向所有连接的 Web 客户端广播一条消息。 尽管目前没有任何 Web 客户端连接到 Web PubSub 资源,但你可以通过启用实时跟踪工具功能来查看此流的实际运行情况,从中可以实时监视重要的日志记录。

在浏览器中接收消息

如果我们未收到广播的消息,则前面的操作就没有意义。 在之前创建的服务器文件夹中,创建一个简单的 HTML 文件,用于放置客户端代码。 express 应用提供该静态文件。

mkdir public && cd public 
touch index.html
复制客户端代码

将代码复制到 index.html

<!DOCTYPE html>

<body>
  <script type="module">
    const endpoint = "http://localhost:3000"

    // Gets an access token through which the client connects with your Web PubSub resource
    const webPubSubUrl = await getWebPubSubAccessToken(endpoint)

    // Opens a WebSocket connection with your Web PubSub resource using browser native WebSocket API 
    const socket = new WebSocket(webPubSubUrl)

    socket.addEventListener("open", () => {
      console.log("connection opened")
    })

    // Prints out the message when it arrives
    socket.addEventListener("message", (msg) => {
      console.log(msg)
    })

    async function getWebPubSubAccessToken(endpoint) {
      const response = await fetch(endpoint + "/negotiate")
      const { url } = await response.json()
      return url
    }
  </script>
</body>

</html>
启动客户端程序

打开你偏好的 Web 浏览器并访问 http://localhost:3000,我们的服务器正在其中侦听。

该屏幕截图显示浏览器客户端直接连接 Web PubSub 资源和本地运行的服务器应用。

确保 publish.js 仍在运行。 如果你检查页面并打开“网络”和“控制台”面板,则会看到客户端已成功连接到 Web PubSub 资源并且正在获取广播的消息。

通过应用程序网关中转 WebSocket 连接

由于应用程序网关原生支持 WebSocket,因此我们不需要更改应用程序网关资源上的任何配置。 只需更改客户端指向的终结点即可。

找到 publish.js 文件并进行两处更改。

  • 声明一个变量来保存应用程序网关资源的公共 IP。
  • 更改初始化变量 url 的行,即 let url=token.url
// ... code omitted from before
const appGatewayEndpoint = process.env.appGatewayEndpoint

app.get("/negotiate", async (req, res) => {
  const token = await webpubsub.getClientAccessToken()
  const url = "ws://" + appGatewayEndpoint + token.url.split(".com")[1]
  // ... code omitted from before
})

// ... code omitted from before

找到应用程序网关资源的公共 IP 并设置环境变量。

export appGatewayEndpoint="<replace with the public IP of your Applciation Gateway resource>"

需要注意三点。

  • 我们使用的是 ws:// 而不是 wss://,因为应用程序网关配置为仅侦听 http 流量。
  • 在生产环境中,最好为应用程序网关资源设置自定义域并将其配置为仅接受 HTTP。
  • 我们需要保留访问令牌,因为它对客户端连接 Web PubSub 资源的凭据进行编码。

打开浏览器并再次访问 http://localhost:3000,可以验证 WebSocket 是否已成功通过应用程序网关中转,并且大约每隔 2 秒从应用程序网关接收一次消息。

该屏幕截图显示浏览器客户端间接连接 Web PubSub 资源和本地运行的服务器应用。

步骤 1 回顾

我们到了步骤 1 的末尾。 如果你一直在遵循步骤 1,则应会看到 Web PubSub 资源可由 Web 客户端直接访问,并且可通过应用程序网关间接访问。 你还看到了应用程序网关对 WebSocket 的原生支持。 无需进行任何配置更改即可启用此支持。 我们只需确保 Web 客户端指向应用程序网关终结点。 Web PubSub 服务 SDK 生成的访问 URL 的其余部分应保持不变。

在步骤 2 中,我们关闭对 Web PubSub 资源的公共访问,以使其更加安全。

步骤 2:禁用对 Web PubSub 资源的公共访问

步骤 1 的结果是 Web PubSub 资源可以通过公共 Internet 和应用程序网关访问。 由于 Web PubSub 资源不在同一虚拟网络中,因此当应用程序网关将流量转发到 Web PubSub 资源时,它会通过公共 Internet 到达 Web PubSub 的公共终结点。 这种情况是不可取的。

Web PubSub 服务支持配置访问控制。 其中一种配置是禁用公共 Internet 的访问。 完成后请务必点击“保存”。

该屏幕截图显示如何禁用 Web PubSub 的公共访问。

现在,如果运行同一命令,则会看到 403 Forbidden,而不是像以前一样看到“无效的中心名称”。

curl https://<your-web-pubsub-resource-endpoint>/client

现在已禁用 Web PubSub 资源的公共访问。 此操作的一个影响是,在步骤 1 中设置的应用程序网关也无法访问该资源。 如果针对应用程序网关终结点运行同一命令,你将看到 504 Gateway Time-out

curl http://<public-ip-of-your-application-gateway-resource>/client

我们需要将 Web PubSub 资源放置在应用程序网关所在的同一虚拟网络中。 我们通过创建专用终结点来实现此目的。 可在此处了解有关专用终结点的详细信息。

为专用终结点创建单独的子网

在步骤 1 中,我们创建了一个用于托管应用程序网关的子网。 应用程序网关需要自己的子网,因此我们需要为专用终结点创建另一个子网。

找到我们之前创建的虚拟网络资源并创建新的子网。

该屏幕截图显示如何创建另一个子网。

为 Web PubSub 资源创建专用终结点

在 Azure 门户上找到你的 Web PubSub 资源并转到“网络”边栏选项卡。 该屏幕截图显示如何创建单独的子网。

在与 Web PubSub 资源相同的区域创建一个专用终结点。 该屏幕截图显示如何为 Web PubSub 资源创建专用终结点。

选择刚刚创建的单独子网。 该屏幕截图显示如何将 Web PubSub 的专用终结点放置在新建的子网中。

启用专用 DNS 集成 该屏幕截图显示如何启用专用 DNS 集成。

刷新应用程序网关资源的后端池

应用程序网关资源不知道为 Web PubSub 资源创建了专用终结点。 找到你的应用程序网关资源并刷新后端池。 该屏幕截图显示如何刷新后端池。

现在,如果再次运行此命令,你应会再次看到“无效的中心名称”,此结果在预料之中。 它表明应用程序网关通过虚拟网络而不是公共 Internet 来中转流量。

curl http://<public-ip-of-your-application-gateway-resource>/client

将发布程序部署为应用服务 Web 应用

由于已禁用 Web PubSub 资源的公共访问,因此我们的本地 publish.js 程序无法访问该资源。 我们需要将该程序作为 Web 应用程序部署到 Web PubSub 资源所在的同一虚拟网络中。

将 Web 应用部署为 ZIP 文件

在将源代码压缩并部署到 Azure 应用服务之前,我们需要对客户端代码做出一项细微的更改。 /negotiate 终结点将不再由 localhost 提供服务。

在公共文件夹中找到 index.html,并更改声明 endpoint 变量的行。 需要将其替换为 Web 应用的域名。

该屏幕截图显示从何处获取 Web 应用资源的域名。

  <script>
    // ...code omitted from before

   const endpoint = "<replace with your default domain name of your web app>"

    // ...code omitted from before
  </script>

Web 应用提供了一个方便的命令用于将应用部署为 ZIP 文件。 你可以详细了解 az webapp up 命令及其自动执行的任务。

找到在步骤 1 中创建的服务器文件夹。

## Makes sure you are in the right working directory
cd server 

## Make sure you have Azure CLI installed and log into your Azure account.
az cloud set -n AzureChinaCloud
az login 
# az cloud set -n AzureCloud   //means return to Public Azure.

## Creates a ZIP file with the content in the server folder and deploys it as a Web App
az webapp up \
--sku B1 \
--name <the-name-of-your-web-app> \
--location <the-same-location-as-your-Web-PubSub-resource>

注意

如果你一直在按照本指南操作,可能需要切换到目前为止创建的资源所在的 Azure 订阅。 若要切换订阅,请按照此文档文章中所述的命令进行操作。

设置环境变量

publish.js 程序启动时,应用服务将提供环境变量以供程序使用。

我们需要设置两个环境变量并提供给 publish.js 使用。

  • 在 Azure 门户上找到到 Web PubSub 服务的连接字符串,并设置 WebPubSubConnectionString 环境变量。
  • 找到应用程序网关资源的前端公共 IP,并设置 appGatewayEndpoint 环境变量。 该屏幕截图显示如何设置 Web 应用的两个环境变量。

在 Web 应用上启用虚拟网络集成

应用服务需要虚拟网络中的专用子网。 转到虚拟网络资源并创建新的子网,就像为 Web PubSub 资源所做的那样。

创建新子网后,转到 Web 应用资源的“网络”边栏选项卡并启用虚拟网络集成。

该屏幕截图显示如何启用虚拟网络集成 - 步骤 1。

确保选择 Web PubSub 资源所在的同一虚拟网络。  该屏幕截图显示如何启用虚拟网络集成 - 步骤 2。

关闭自动 HTTP 重定向

默认情况下,Web 应用将 HTTP 流量重定向到 HTTPs。 我们需要禁用此默认行为。 对于生产工作负载,不建议这样做。 该屏幕截图显示如何关闭自动 HTTPs 重定向。

验证是否一切正常

到目前为止,在步骤 2 中:

  1. 禁用了对 Web PubSub 资源的公共访问;
  2. 为其创建了一个专用终结点;
  3. 刷新了应用程序网关资源的后端池,以便它可以访问你的 Web PubSub 资源
  4. 更新了由客户端用来获取访问令牌(用于连接 Web PubSub 资源)的终结点
  5. publish.js 作为 Web 应用部署到了同一虚拟网络中;
  6. 在 Web 应用资源上设置了两个环境变量;
  7. 禁用了 Web 应用将 HTTP 流量重定向到 HTTPs 的默认行为。

现在,打开 Web 浏览器并输入 Web 应用的域名。 如果你检查页面并打开“网络”面板,将会看到客户端转到 Web 应用获取访问令牌,然后使用该令牌通过应用程序网关建立 WebSocket 连接。

该屏幕截图显示如何从 Web 应用获取访问令牌。

该屏幕截图显示已通过应用程序网关成功建立 WebSocket 连接。

如果打开了“控制台”面板,则还会看到广播的消息。 该屏幕截图显示从中转 Web PubSub 流量的应用程序网关获取消息。