共用方式為


教學課程 - 使用事件處理程式根據用戶端憑證驗證和授權 MQTT 用戶端

在本教學課程中,您將瞭解如何撰寫 .NET 網頁伺服器來驗證和授權 MQTT 用戶端。

必要條件

  • 具有有效訂用帳戶的 Azure 帳戶。 如果您沒有 Azure 帳戶,可以免費建立帳戶
  • Azure Web PubSub 服務 (必須是標準層以上)。
  • PEM 格式的客戶端憑證。
  • 已安裝 .NET 執行階段
  • Node.js

部署 Azure Web PubSub 服務

以下是 Bicep/Azure Resource Manager 範本,可部署已啟用用戶端憑證驗證並設定事件處理程式的 Azure Web PubSub 服務。

我們會設定 connect 事件處理程式,告知服務 Webhook 端點進行驗證和授權。 我們將設定為 tunnel:///MqttConnecttunnel://是利用 awps 通道工具將本機驗證伺服器公開至公用網路的特殊語法/MqttConnect 是將由本機驗證伺服器公開的端點。

我們會透過 屬性 tls.clientCertEnabled 啟用用戶端憑證驗證,以便在事件中 connect 將客戶端憑證傳送至您的伺服器。

另外請注意,anonymousConnectPolicy 必須設定為 allow,用戶端才不必再傳送存取權杖。

param name string
param hubName string = 'hub1'
param eventHandlerUrl string = 'tunnel:///MqttConnect'
param location string = resourceGroup().location

resource awps 'Microsoft.SignalRService/WebPubSub@2023-03-01-preview' = {
  name: name
  location: location
  sku: {
    name: 'Standard_S1'
    tier: 'Standard'
    size: 'S1'
    capacity: 1
  }
  properties: {
    tls: {
      clientCertEnabled: true
    }
  }
}

resource hub 'Microsoft.SignalRService/WebPubSub/hubs@2023-03-01-preview' = {
  parent: awps
  name: '${hubName}'
  properties: {
    eventHandlers: [
      {
        urlTemplate: eventHandlerUrl
        userEventPattern: '*'
        systemEvents: [
          'connect'
        ]
      }
    ]
    anonymousConnectPolicy: 'allow'
  }
}

設定驗證伺服器

我們在這裡提供了驗證伺服器範例。 請下載專案。

讓我們看看項目結構:

- mqttAuthServer
  - Models
    - MqttConnectEventRequest.cs
    - ...
  - MqttAuthServer.csproj
  - Program.cs

目錄 Models 包含所有模型檔案,以描述 MQTT connect 事件的要求和回應本文。 Program.cs包含處理 MQTT connect 事件的邏輯,包括從要求剖析用戶端憑證內容、驗證憑證,以及授權用戶端。

下列代碼段是處理 connect 事件要求的主要邏輯:

    var request = await httpContext.Request.ReadFromJsonAsync<MqttConnectEventRequest>();
    var certificates = request.ClientCertificates.Select(cert => GetCertificateFromPemString(cert.Content));
    // Simulate Logic to validate client certificate
    if (!request.Query.TryGetValue("failure", out _))
    {
        // As a demo, we just accept all client certificates and grant the clients with permissions to publish and subscribe to all the topics when the query parameter "success" is present.
        await httpContext.Response.WriteAsJsonAsync(new MqttConnectEventSuccessResponse()
        {
            Roles = ["webpubsub.joinLeaveGroup", "webpubsub.sendToGroup"]
        });
    }
    else
    {
        // If you want to reject the connection, you can return a MqttConnectEventFailureResponse
        var mqttCodeForUnauthorized = request.Mqtt.ProtocolVersion switch
        {
            4 => 5, // UnAuthorized Return Code in Mqtt 3.1.1
            5 => 0x87, // UnAuthorized Reason Code in Mqtt 5.0
            _ => throw new NotSupportedException($"{request.Mqtt.ProtocolVersion} is not supported.")
        };
        httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        await httpContext.Response.WriteAsJsonAsync(new MqttConnectEventFailureResponse(new MqttConnectEventFailureResponseProperties()
        {
            Code = mqttCodeForUnauthorized,
            Reason = "Invalid Certificate"
        }
        ));
    }

若要執行專案,請在根目錄中執行下列命令。

dotnet run

將伺服器端點公開至公用網路

下載並安裝 awps-tunnel

此工具執行於 Node.js 16 版或更新版本上。

npm install -g @azure/web-pubsub-tunnel-tool

使用服務連接字串並執行

export WebPubSubConnectionString="<your connection string>"
awps-tunnel run --hub {hubName} --upstream http://localhost:{portExposedByYourAuthServer}

實作 MQTT 用戶端

我們將在 Node.js 中實作用戶端。

使用下列命令初始化Node.js專案。

npm init

安裝模組 mqtt

npm install mqtt

建立名為 index.js的新檔案,並將下列程式代碼新增至 檔案。

const mqtt = require('mqtt');

var client = mqtt.connect(`wss://{serviceName}.webpubsub.azure.com/clients/mqtt/hubs/{hubName}`,
    {
        clientId: "client1",
        cert: `-----BEGIN CERTIFICATE-----
{Complete the certificate here}
-----END CERTIFICATE-----`,
        key: `-----BEGIN PRIVATE KEY-----
{Complete the private key here}
-----END PRIVATE KEY-----`,
        protocolVersion: 5,
    });
client.on("connect", (connack) => {
    console.log("connack", connack);
});
client.on("error", (err) => {
    console.log(err);
});

更新 :index.js

  • 根據您所建立的資源更新 {serviceName}{hubName} 變數。
  • 完成檔案中的客戶端憑證和金鑰。

然後,您可以使用 命令執行專案

node index.js

如果一切正常運作,您將能夠看到控制台中列印成功的 CONNACK 回應。

connack Packet {
  cmd: 'connack',
  retain: false,
  qos: 0,
  dup: false,
  length: 2,
  topic: null,
  payload: null,
  sessionPresent: false,
  returnCode: 0
}

若要模擬憑證驗證失敗,請將失敗查詢附加至連線 URL,如下所示

var client = mqtt.connect(`wss://{serviceName}.webpubsub.azure.com/clients/mqtt/hubs/{hubName}?failure=xxx`,

然後重新執行用戶端,您將可以看到未經授權的 CONNACK 回應。

後續步驟

現在您已知道如何驗證和授權 MQTT 用戶端 e2e。 接下來,您可以檢查 MQTT 用戶端的事件處理程式通訊協定。