英語で読む

次の方法で共有


チュートリアル - イベント ハンドラーを使用し、クライアント証明書に基づいて MQTT クライアントの認証と認可を行う

このチュートリアルでは、MQTT クライアントの認証と認可を行う .NET Web サーバーを作成する方法について説明します。

前提条件

  • アクティブなサブスクリプションが含まれる Azure アカウント。 Azure アカウントをお持ちでない場合は、無料でアカウントを作成することができます。
  • Azure Web PubSub サービス (Standard レベル以上である必要があります)。
  • PEM 形式のクライアント証明書。
  • .NET ランタイムがインストールされている。
  • Node.js

Azure Web PubSub サービスをデプロイする

ここでは、クライアント証明書認証が有効でイベント ハンドラーが構成された Azure Web PubSub サービスをデプロイするための Bicep と Azure Resource Manager のテンプレートを示します。

connect イベント ハンドラーを構成して、クライアントの認証と認可のための Webhook エンドポイントをサービスに通知します。 それを tunnel:///MqttConnect に設定します。 tunnel:// は、awps-tunnel ツールを利用してローカル認証サーバーをパブリック ネットワークに公開する特別な構文です。 /MqttConnect は、ローカル認証サーバーによって公開されるエンドポイントです。

クライアント証明書が connect イベントでサーバーに送信されるように、プロパティ tls.clientCertEnabled を使ってクライアント証明書認証を有効にします。

また、クライアントがアクセス トークンを送信する必要がなくなるように、anonymousConnectPolicyallow に設定する必要があることにも注意してください。

Bicep
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 イベント要求を処理する主なロジックです。

cs
    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"
        }
        ));
    }

プロジェクトを実行するには、ルート ディレクトリで次のコマンドを実行します。

.NET CLI
dotnet run

サーバー エンドポイントをパブリック ネットワークに公開する

awps-tunnel をダウンロードしてインストールする

このツールは、Node.js バージョン 16 以降で実行されます。

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

サービス接続文字列を使って実行する

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

MQTT クライアントを実装する

Node.js でクライアント側を実装します。

次のコマンドを使って、新しい Node.js プロジェクトを初期化します。

Bash
npm init

mqtt モジュールをインストールします。

Bash
npm install mqtt

index.jsという名前の新しいファイルを作成して、次のコードをファイルに追加します。

JavaScript
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} 変数を更新します。
  • ファイルのクライアント証明書とキーを完成させます。

その後、コマンドを使ってプロジェクトを実行できます。

Bash
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 に誤ったクエリを追加します

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

クライアントを実行し直すと、認可されていない CONNACK 応答が表示されます。

次のステップ

これで、MQTT クライアント e2e の認証と認可を行う方法がわかりました。 次に、MQTT クライアントのイベント ハンドラー プロトコルを調べることができます。