クイック・セキュア CoAP クライアント
CoAPクライアントのセキュリティ対策を施し、Qt Quick のユーザーインターフェースで利用する方法。

「Quick Secure CoAP Client」では、セキュアなCoAPクライアントを作成し、Qt Quick アプリケーションでそれを使用する方法について解説します。
注: Qt CoAP の 現行バージョンでは、QML APIは提供されていません。ただし、この例に示されているように、モジュールのC++クラスをQMLから利用できるようにすることは可能です。
例の動作確認
以下の手順でサンプルを実行できます。
- Qt Creator
Welcome モードを開き、Examples からこのサンプルを選択します。詳細については、Qt Creator の「チュートリアル:ビルドと実行」を参照してください。
- Qt Extension for Visual Studio Code
Command Palette から `Qt: Open Qt examples ` コマンドを実行し、リストから例を選択します。詳細については、Qt Extension for Visual Studio Code: チュートリアル: ビルドと実行を参照してください。
サンプルアプリケーションを実行するには、まずセキュアな CoAP サーバーを設定する必要があります。このサンプルは、事前共有鍵 (PSK) または証明書認証モードのいずれかをサポートするセキュアな CoAP サーバーであれば、どれでも実行可能です。セキュアな CoAP サーバーの設定に関する詳細については、「セキュアな CoAP サーバーの設定」を参照してください。
C++ クラスを QML から利用可能にする
この例では、QCoapClient クラスとQtCoap 名前空間をQMLに公開する必要があります。これを実現するには、カスタムラッパークラスを作成し、専用の登録マクロを使用します。
`QCoapClient` をラップする `QmlCoapSecureClient ` クラスを作成します。このクラスは、選択されたセキュリティモードとセキュリティ設定パラメータも保持します。`Q_INVOKABLE ` マクロを使用して、いくつかのメソッドを QML に公開します。また、`QML_NAMED_ELEMENT ` マクロを使用して、QML 内でこのクラスを `CoapSecureClient` として登録します。
class QmlCoapSecureClient : public QObject
{
Q_OBJECT
QML_NAMED_ELEMENT(CoapSecureClient)
public:
QmlCoapSecureClient(QObject *parent = nullptr);
~QmlCoapSecureClient() override;
Q_INVOKABLE void setSecurityMode(QtCoap::SecurityMode mode);
Q_INVOKABLE void sendGetRequest(const QString &host, const QString &path, int port);
Q_INVOKABLE void setSecurityConfiguration(const QString &preSharedKey, const QString &identity);
Q_INVOKABLE void setSecurityConfiguration(const QString &localCertificatePath,
const QString &caCertificatePath,
const QString &privateKeyPath);
Q_INVOKABLE void disconnect();
Q_SIGNALS:
void finished(const QString &result);
private:
QCoapClient *m_coapClient;
QCoapSecurityConfiguration m_configuration;
QtCoap::SecurityMode m_securityMode;
};その後、QtCoap 名前空間を登録し、そこに用意されている列挙型を使用できるようにします:
namespace QCoapForeignNamespace
{
Q_NAMESPACE
QML_FOREIGN_NAMESPACE(QtCoap)
QML_NAMED_ELEMENT(QtCoap)
}ビルドファイルの調整
QML からカスタム型を利用できるようにするには、ビルドシステムファイルを適宜更新してください。
CMake
CMake ベースのビルドでは、CMakeLists.txt に以下を追加します:
qt_add_qml_module(quicksecureclient
URI CoapSecureClientModule
SOURCES
qmlcoapsecureclient.cpp qmlcoapsecureclient.h
QML_FILES
FilePicker.qml
Main.qml
)qmake
qmake によるビルドの場合は、quicksecureclient.pro ファイルを次のように変更してください:
CONFIG += qmltypes
QML_IMPORT_NAME = CoapSecureClientModule
QML_IMPORT_MAJOR_VERSION = 1
...
qml_resources.files = \
qmldir \
FilePicker.qml \
Main.qml
qml_resources.prefix = /qt/qml/CoapSecureClientModule
RESOURCES += qml_resources新しいQMLタイプの使用
これで、C++ クラスが QML に対して適切に公開されたため、新しい型を使用できるようになります。
クライアントの作成
CoapSecureClient は、Main.qml ファイルからインスタンス化されます。これはQmlCoapSecureClient::finished() シグナルを処理し、それに応じて UI を更新します:
CoapSecureClient {
id: client
onFinished: (result) => {
outputView.text = result;
statusLabel.text = "";
disconnectButton.enabled = true;
}
}QCoapClient のインスタンスは、ユーザーがUIでセキュリティモードを選択または変更した際に作成されます。QmlCoapSecureClient::setSecurityMode() メソッドは、いずれかのセキュリティモードが選択された際に、QMLコードから呼び出されます:
ButtonGroup {
id: securityModeGroup
onClicked: {
if ((securityModeGroup.checkedButton as RadioButton) === preSharedMode)
client.setSecurityMode(QtCoap.SecurityMode.PreSharedKey);
else
client.setSecurityMode(QtCoap.SecurityMode.Certificate);
}
}C++側では、このメソッドがQCoapClient を作成し、そのfinished()およびerror()シグナルに接続します。このクラスは両方のシグナルを内部で処理し、新しいfinished() シグナルに転送します。
void QmlCoapSecureClient::setSecurityMode(QtCoap::SecurityMode mode)
{
// Create a new client, if the security mode has changed
if (m_coapClient && mode != m_securityMode) {
delete m_coapClient;
m_coapClient = nullptr;
}
if (!m_coapClient) {
m_coapClient = new QCoapClient(mode);
m_securityMode = mode;
connect(m_coapClient, &QCoapClient::finished, this,
[this](QCoapReply *reply) {
if (!reply)
emit finished(tr("Something went wrong, received a null reply"));
else if (reply->errorReceived() != QtCoap::Error::Ok)
emit finished(errorMessage(reply->errorReceived()));
else
emit finished(reply->message().payload());
});
connect(m_coapClient, &QCoapClient::error, this,
[this](QCoapReply *, QtCoap::Error errorCode) {
emit finished(errorMessage(errorCode));
});
}
}リクエストの送信
「Send Request 」ボタンをクリックして、選択したセキュリティモードに基づいてセキュリティ設定を行い、「GET 」リクエストを送信します:
Button {
id: requestButton
text: qsTr("Send Request")
enabled: securityModeGroup.checkState !== Qt.Unchecked
onClicked: {
outputView.text = "";
if ((securityModeGroup.checkedButton as RadioButton) === preSharedMode)
client.setSecurityConfiguration(pskField.text, identityField.text);
else
client.setSecurityConfiguration(localCertificatePicker.selectedFile,
caCertificatePicker.selectedFile,
privateKeyPicker.selectedFile);
client.sendGetRequest(hostComboBox.editText, resourceField.text,
parseInt(portField.text));
statusLabel.text = qsTr("Sending request to %1%2...").arg(hostComboBox.editText)
.arg(resourceField.text);
}
}setSecurityConfiguration メソッドには 2 つのオーバーロードがあります。
PSKモード用のオーバーロードは、クライアントIDと事前共有鍵を設定するだけです:
void
QmlCoapSecureClient::setSecurityConfiguration(const QString &preSharedKey, const QString &identity)
{
QCoapSecurityConfiguration configuration;
configuration.setPreSharedKey(preSharedKey.toUtf8());
configuration.setPreSharedKeyIdentity(identity.toUtf8());
m_configuration = configuration;
}一方、X.509証明書用のオーバーロードは、証明書ファイルと秘密鍵を読み込み、セキュリティ設定を行います:
void QmlCoapSecureClient::setSecurityConfiguration(const QString &localCertificatePath,
const QString &caCertificatePath,
const QString &privateKeyPath)
{
QCoapSecurityConfiguration configuration;
const auto localCerts =
QSslCertificate::fromPath(QUrl(localCertificatePath).toLocalFile(), QSsl::Pem,
QSslCertificate::PatternSyntax::FixedString);
if (localCerts.isEmpty())
qCWarning(lcCoapClient, "The specified local certificate file is not valid.");
else
configuration.setLocalCertificateChain(localCerts.toVector());
const auto caCerts = QSslCertificate::fromPath(QUrl(caCertificatePath).toLocalFile(), QSsl::Pem,
QSslCertificate::PatternSyntax::FixedString);
if (caCerts.isEmpty())
qCWarning(lcCoapClient, "The specified CA certificate file is not valid.");
else
configuration.setCaCertificates(caCerts.toVector());
QFile privateKey(QUrl(privateKeyPath).toLocalFile());
if (privateKey.open(QIODevice::ReadOnly)) {
QCoapPrivateKey key(privateKey.readAll(), QSsl::Ec);
configuration.setPrivateKey(key);
} else {
qCWarning(lcCoapClient) << "Unable to read the specified private key file"
<< privateKeyPath;
}
m_configuration = configuration;
}セキュリティ設定の設定後、sendGetRequest メソッドはリクエストURLを設定し、GET リクエストを送信します:
void QmlCoapSecureClient::sendGetRequest(const QString &host, const QString &path, int port)
{
if (!m_coapClient)
return;
m_coapClient->setSecurityConfiguration(m_configuration);
QUrl url;
url.setHost(host);
url.setPath(path);
url.setPort(port);
m_coapClient->get(url);
}最初のリクエストを送信する際、CoAPサーバーとのハンドシェイクが行われます。ハンドシェイクが正常に完了すると、それ以降のすべてのメッセージは暗号化され、ハンドシェイク成功後にセキュリティ設定を変更しても何の効果もありません。設定を変更したり、ホストを変更したりしたい場合は、まず接続を切断する必要があります。
void QmlCoapSecureClient::disconnect()
{
if (m_coapClient)
m_coapClient->disconnect();
}これにより、ハンドシェイクが中止され、開いているソケットが閉じられます。
X.509証明書を使用した認証を行うには、証明書ファイルを指定する必要があります。この目的には、FilePicker コンポーネントが使用されます。このコンポーネントは、テキストフィールドと、ボタンが押された際にファイルダイアログを開くためのボタンを組み合わせています:
Item {
id: filePicker
property string dialogText
property alias selectedFile: filePathField.text
height: addFileButton.height
FileDialog {
id: fileDialog
title: qsTr("Please Choose %1").arg(filePicker.dialogText)
currentFolder: StandardPaths.writableLocation(StandardPaths.HomeLocation)
fileMode: FileDialog.OpenFile
onAccepted: filePathField.text = fileDialog.selectedFile
}
RowLayout {
anchors.fill: parent
TextField {
id: filePathField
placeholderText: qsTr("<%1>").arg(filePicker.dialogText)
inputMethodHints: Qt.ImhUrlCharactersOnly
selectByMouse: true
Layout.fillWidth: true
}
Button {
id: addFileButton
text: qsTr("Add %1").arg(filePicker.dialogText)
onClicked: fileDialog.open()
}
}
}FilePicker Main.qml ファイル内では、証明書および秘密鍵用の入力フィールドを作成するために、このコンポーネントが複数回インスタンス化されています:
FilePicker {
id: localCertificatePicker
dialogText: qsTr("Local Certificate")
enabled: (securityModeGroup.checkedButton as RadioButton) === certificateMode
Layout.columnSpan: 2
Layout.fillWidth: true
}
FilePicker {
id: caCertificatePicker
dialogText: qsTr("CA Certificate")
enabled: (securityModeGroup.checkedButton as RadioButton) === certificateMode
Layout.columnSpan: 2
Layout.fillWidth: true
}
FilePicker {
id: privateKeyPicker
dialogText: qsTr("Private Key")
enabled: (securityModeGroup.checkedButton as RadioButton) === certificateMode
Layout.columnSpan: 2
Layout.fillWidth: true
}セキュアな CoAP サーバーの設定
このサンプルを実行するには、PSK モードまたは証明書モード(あるいはその両方)をサポートするセキュアな CoAP サーバーが必要です。以下のオプションがあります:
- libcoap、Californium、FreeCoAP、またはDTLSをサポートするその他のCoAPライブラリなどを使用して、手動でセキュアなCoAPサーバーを構築・実行する。
- Docker Hub で入手可能な既製の Docker イメージを使用します。これらは、この例に適したセキュアな CoAP サーバーを構築・実行します。Docker ベースの CoAP サーバーを使用するために必要な手順を以下に説明します。
PSKモード用サーバーの設定
次のコマンドを実行すると、Docker Hub からCalifornium plugtest(デフォルトではセキュリティ対応ではありません)をベースにしたセキュアな CoAP サーバー用の Docker コンテナを取得し、起動します。
docker run --name coap-test-server -d --rm -p 5683:5683/udp -p 5684:5684/udp tqtc/coap-californium-test-server:3.8.0CoAP テストサーバーには、ポート5683(非セキュア)および5684(セキュア)からアクセスできます。IP アドレスの取得方法については、「IP アドレスの取得」を参照してください。
このサーバーでサンプルを実行するには、事前共有キーを `secretPSK `、IDを `Client_identity` に設定する必要があります。
証明書モード用のサーバーの設定
X.509証明書による認証を使用するセキュアサーバーのDockerイメージは、FreeCoAPライブラリのタイムサーバーの例に基づいています。次のコマンドで、Docker Hubからコンテナを取得して起動します。
docker run --name coap-time-server -d --rm -p 5684:5684/udp tqtc/coap-secure-time-server:freecoapIP アドレスの取得方法については、「IP アドレスの取得」を参照してください。CoAP テストサーバーには、取得した IP アドレスのポート5684およびリソースパス/time からアクセスできます。
このサーバーでサンプルを実行するには、サーバーが必要とする証明書ファイルを指定する必要があります。これらのファイルは、Dockerコンテナ内の/root/certs ディレクトリにあります。それらをローカルディレクトリにコピーするには、次のコマンドを使用します:
docker cp <container_id>:/root/certs <local_directory_path>例:
$ docker cp 5e46502df88f:/root/certs ~/コンテナIDの取得方法については、以下で説明します。
IPアドレスの取得
DockerコンテナのIPアドレスを確認するには、まずdocker ps コマンドを実行してコンテナIDを取得します。これにより、次のような出力が表示されます:
$ docker ps
CONTAINER ID IMAGE
5e46502df88f tqtc/coap-californium-test-server:3.8.0その後、次のコマンドで IP アドレスを取得できます:
docker inspect <container_id> | grep IPAddress例:
$ docker inspect 5e46502df88f | grep IPAddress
...
"IPAddress": "172.17.0.2",
...Dockerコンテナの終了
使用後のDockerコンテナを終了するには、次のコマンドを使用します:
docker stop <container_id>ここでいう `<container_id> ` は、`docker ps ` コマンドで取得したIDと同じものです。
ファイル:
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.