X.509凭据认证
X.509基于证书的身份验证用于双向SSL连接。在这种情况下证书本身就是客户端的ID,因此不再需要访问令牌。
以下说明将描述如何生成客户端证书以及如何通过SSL连接到运行MQTT的服务器。你将需要具有PEM格式的服务器证书的公钥。有关服务器端配置的更多详细信息请参见以下说明。
更新keygen.properties文件
打 keygen.properties文件并根据需要更新对应内容:
DOMAIN_SUFFIX="$(hostname)"
ORGANIZATIONAL_UNIT=ThingsBoard
ORGANIZATION=ThingsBoard
CITY=San Francisco
STATE_OR_PROVINCE=CA
TWO_LETTER_COUNTRY_CODE=US
SERVER_KEYSTORE_PASSWORD=server_ks_password
SERVER_KEY_PASSWORD=server_key_password
SERVER_KEY_ALIAS="serveralias"
SERVER_FILE_PREFIX="mqttserver"
SERVER_KEYSTORE_DIR="/etc/thingsboard/conf/"
CLIENT_KEYSTORE_PASSWORD=password
CLIENT_KEY_PASSWORD=password
CLIENT_KEY_ALIAS="clientalias"
CLIENT_FILE_PREFIX="mqttclient"
运行客户端密钥生成脚本
下载并启动client.keygen.sh脚本。
chmod +x client.keygen.sh
./client.keygen.sh
该脚本输出以下文件:
- CLIENT_FILE_PREFIX.jks - 导入了服务器证书的Java密钥库文件
- CLIENT_FILE_PREFIX.nopass.pem - 非Java客户端使用的PEM格式的客户端证书文件
- CLIENT_FILE_PREFIX.pub.pem - 客户端公共钥
将客户端公钥设置为设备凭据
ThingsBoard Web UI -> Devices -> Your Device -> Device Credentials. 选择X.509凭据, 插入CLIENT_FILE_PREFIX.pub.pem 文件内容并保存或者通过REST API进行相同操作。
运行双向MQTT SSL Python客户端
下载Python客户端示例two-way-ssl-mqtt-client.py。
指定你的客户端证书和服务器证书公钥的路径。
# Some code omitted
client.tls_set(ca_certs="mqttserver.pub.pem", certfile="mqttclient.nopass.pem", keyfile=None, cert_reqs=ssl.CERT_REQUIRED,
tls_version=ssl.PROTOCOL_TLSv1, ciphers=None);
# Some code omitted
注意 脚本使用 8883 mqtt端口和需要paho mqtt库你可以使用以下命令进行安装:pip install paho-mqtt
运行脚本:
如果一切配置正确,则输出应为:
To run Java client, import CLIENT_FILE_PREFIX.jks file as follows:
resources/MqttSslClient.java  |
import com.google.common.io.Resources;
import org.eclipse.paho.client.mqttv3.*;
import javax.net.ssl.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.*;
import java.security.cert.CertificateException;
public class MqttSslClient {
private static final String MQTT_URL = "ssl://localhost:8883";
private static final String clientId = "MQTT_SSL_JAVA_CLIENT";
private static final String keyStoreFile = "mqttclient.jks";
private static final String JKS="JKS";
private static final String TLS="TLS";
private static final String CLIENT_KEYSTORE_PASSWORD = "password";
private static final String CLIENT_KEY_PASSWORD = "password";
public static void main(String[] args) {
try {
URL ksUrl = Resources.getResource(keyStoreFile);
File ksFile = new File(ksUrl.toURI());
URL tsUrl = Resources.getResource(keyStoreFile);
File tsFile = new File(tsUrl.toURI());
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore trustStore = KeyStore.getInstance(JKS);
trustStore.load(new FileInputStream(tsFile), CLIENT_KEYSTORE_PASSWORD.toCharArray());
tmf.init(trustStore);
KeyStore ks = KeyStore.getInstance(JKS);
ks.load(new FileInputStream(ksFile), CLIENT_KEYSTORE_PASSWORD.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, CLIENT_KEY_PASSWORD.toCharArray());
KeyManager[] km = kmf.getKeyManagers();
TrustManager[] tm = tmf.getTrustManagers();
SSLContext sslContext = SSLContext.getInstance(TLS);
sslContext.init(km, tm, null);
MqttConnectOptions options = new MqttConnectOptions();
options.setSocketFactory(sslContext.getSocketFactory());
MqttAsyncClient client = new MqttAsyncClient(MQTT_URL, clientId);
client.connect(options);
Thread.sleep(3000);
MqttMessage message = new MqttMessage();
message.setPayload("{\"key1\":\"value1\", \"key2\":true, \"key3\": 3.0, \"key4\": 4}".getBytes());
client.publish("v1/devices/me/telemetry", message);
client.disconnect();
System.out.println("Disconnected");
System.exit(0);
} catch (Exception e) {
e.printStackTrace();
}
}
}
|