MQTTnet入门(三) - 使用证书创建SSL加密端口
文章目录
- MQTTnet入门(三) - 使用证书创建SSL加密端口
- 前言
- 使用证书创建SSL加密端口Demo
- 附录一:Win10下的Ubuntu子系统
- 附录二:MQTTnet API - Server Options
- MqttServerOptionsBuilder类
- 构建选项类
- 允许处理来自客户端的所有已发布消息
- 允许处理来自客户端的所有已发布消息
- 设置用于服务器的客户端ID
- 设置要保留的连接数
- 启用自定义的处理程序验证连接
- 启用自定义的处理程序验证连接
- 设置服务器的默认的通信超时时长
- 服务器启用默认端口
- 设置服务器使用默认端口的IPv4地址
- 设置服务器使用默认端口的IPv6地址
- 服务器启用默认加密端口
- 服务器启用加密端口
- 设置服务器使用加密端口的IPv4地址
- 设置服务器使用加密端口的IPv6地址
- 设置服务器用于SSL加密连接的端口号
- 设置服务器用于SSL加密连接的证书
- 设置服务器用于加密的SSL协议类型
- 告诉服务器允许每个客户端最大的挂起消息
- 允许服务器保留会话
- 允许服务器使用存储
- 允许处理来自客户端的所有订阅
- 允许处理来自客户端的所有订阅
- 禁用默认(非SSL)端口
- 禁用默认(SSL)端口
前言
在上一篇《MQTTnet入门(二) - 验证来自MQTT客户端的连接请求》中,实现了MQTT服务器对客户端连接请求的验证,然而在1883端口上采用的是最原始的TCP方式连接,这是极不安全的,本章会给出使用证书创建SSL加密端口并通信的完整示例,并且尽可能详尽的描述作者在实现该例程时所做的所有工作。
使用证书创建SSL加密端口Demo
创建证书
我们需要创建用于MQTT通信加密的证书,OpenSSL最常用的证书生成工具之一,我所使用的OpenSSL是运行在Linux下的命令行工具,但我相信大多数.Net Core的开发者还是在Windows平台下进行开发,好在Win10集成的Ubuntu子系统,因此我们可以不必运行虚拟机或是云服务去执行我们的OpenSSL。Win10下运行Ubuntu与本无关联不大,我将详细步骤放在了附录中,有需要可以自行翻阅。
启动Win10下的Ubuntu后,进入/mnt/ 会看见Windows的磁盘驱动器都挂载在了这里,因此我们可以从这里访问到我们要创建证书的路径。
若尚未安装OpenSSL,可使用命令“sudo apt-get install openssl”快速安装。
创建证书命令示例(提示:创建过程中会要求输入密码和证书创建者信息,请妥善保管密码。):
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
openssl pkcs12 -export -out certificate.pfx -inkey key.pem -in cert.pem
如此,证书及密钥对就创建完成了:
编写MQTT服务端代码
代码是基于上一篇Demo进行的改进,运行前需修改证书文件“certificate.pfx”的路径,设置证书密码。
using MQTTnet;
using MQTTnet.Protocol;
using MQTTnet.Server;
using System;
using System.IO;
using System.Reflection;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
namespace MQTT
{
class Program
{
private const string CERTIFICATE_FILE_PATH = "./certificate.pfx"; // 证书文件路径
private const string CERTIFICATE_PASSWORD = "创建证书时的密码"; // 证书文件密匙
private const UInt16 EncryptedEndpointPort = 1884; // 加密端口号
static async System.Threading.Tasks.Task Main(string[] args)
{
// 创建MQTT服务配置的构建器
MqttServerOptionsBuilder optionsBuilder = new MqttServerOptionsBuilder();
// 读取证书文件
X509Certificate2 certificate = new X509Certificate2(CERTIFICATE_FILE_PATH, CERTIFICATE_PASSWORD, X509KeyStorageFlags.Exportable);
// 关闭默认端口(1883端口)
optionsBuilder.WithoutDefaultEndpoint();
// 启用加密端口
optionsBuilder.WithEncryptedEndpoint();
// 设置加密端口号
optionsBuilder.WithEncryptedEndpointPort(EncryptedEndpointPort);
// 设置加密端口所使用的证书
optionsBuilder.WithEncryptionCertificate(certificate.Export(X509ContentType.Pfx));
// 设置加密端口所使用的SSL协议
optionsBuilder.WithEncryptionSslProtocol(SslProtocols.Tls12);
// 为构建器添加连接验证的处理过程
optionsBuilder.WithConnectionValidator(context => {
// 验证ClientID的长度
if (context.ClientId.Length < 10)
{
context.ReasonCode = MqttConnectReasonCode.ClientIdentifierNotValid;
return;
}
// 验证用户名和密码
if (context.Username != "user01" || context.Password != "123456")
{
context.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
return;
}
// 标记当前连接请求的ReasonCode为Success
context.ReasonCode = MqttConnectReasonCode.Success;
});
// 利用MqttFactory创建MQTT服务器
IMqttServer mqttServer = new MqttFactory().CreateMqttServer();
// 采用异步方式启动服务(使用服务配置构建器创建的对象)
await mqttServer.StartAsync(optionsBuilder.Build());
Console.WriteLine("按任意键退出程序...");
Console.ReadLine();
// 异步关闭MQTT服务
await mqttServer.StopAsync();
}
}
}
连接测试
测试用的MQTT客户端是MQTT.FX,填写连接信息:
MQTT.FX是一款用Java开发的跨平台的MQTT可视化客户端,功能全面,便于调试。
下载地址:http://mqttfx.bceapp.com/
与MQTT服务端连接成功:
附录一:Win10下的Ubuntu子系统
打开Microsoft Store。
搜索关键字“Ubuntu”,选择想要安装的版本,单击获取。
从控制面板中打开“程序”,打开“启用或关闭Windows功能”
勾选“适用于Linux的Windows子系统”,完成后重启。
重启完成后,打开安装完成的Ubuntu就OK啦~
附录二:MQTTnet API - Server Options
MqttServerOptionsBuilder类
构建选项类
Description: Builds the options class.
方法原型:Build()
允许处理来自客户端的所有已发布消息
Description: Allows to work with all published messaged from the clients.
方法原型:WithApplicationMessageInterceptor(IMqttServerApplicationMessageInterceptor value)
允许处理来自客户端的所有已发布消息
Description: Allows to work with all published messaged from the clients.
方法原型:WithApplicationMessageInterceptor(Action value)
设置用于服务器的客户端ID
Description: Sets the client id used for the server.
方法原型:WithClientId(string value)
设置要保留的连接数
Description: Sets the number of connections to keep.
方法原型:WithConnectionBacklog(int value)
启用自定义的处理程序验证连接
Description: Allows to validate connections with a custom handler.
方法原型:WithConnectionValidator(IMqttServerConnectionValidator value)
启用自定义的处理程序验证连接
Description: Allows to validate connections with a custom handler.
方法原型:WithConnectionValidator(Action value)
设置服务器的默认的通信超时时长
Description: Tells the server to use the default communication timeout.
方法原型:WithDefaultCommunicationTimeout(TimeSpan value)
服务器启用默认端口
Description: Tells the server to use the default endpoint.
方法原型:WithDefaultEndpoint()
设置服务器使用默认端口的IPv4地址
Description: Tells the server to use the default endpoint IPv4 address.
方法原型:WithDefaultEndpointBoundIPAddress(IPAddress value)
设置服务器使用默认端口的IPv6地址
Description: Tells the server to use the default endpoint IPv6 address.
方法原型:WithDefaultEndpointBoundIPV6Address(IPAddress value)Tells the server to use the default endpoint IPv6 address.
服务器启用默认加密端口
Description: Tells the server to use the default endpoint port.
方法原型:WithDefaultEndpointPort(int value)
服务器启用加密端口
Description: Tells the server to use the encrypted endpoint.
方法原型:WithEncryptedEndpoint()
设置服务器使用加密端口的IPv4地址
Description:
方法原型:WithEncryptedEndpointBoundIPAddress(IPAddress value)
设置服务器使用加密端口的IPv6地址
Description: Tells the server to use the encrypted endpoint IPv6 address.
方法原型:WithEncryptedEndpointBoundIPV6Address(IPAddress value)
设置服务器用于SSL加密连接的端口号
Description: Tells the server to use the encrypted endpoint port.
方法原型:WithEncryptedEndpointPort(int value)
设置服务器用于SSL加密连接的证书
Description: Tells the server to use the certificate for SSL connections.
方法原型:WithEncryptionCertificate(byte[] value)
设置服务器用于加密的SSL协议类型
Description: Tells the server to use the SSL protocol level.
方法原型:WithEncryptionSslProtocol(SslProtocols value)
告诉服务器允许每个客户端最大的挂起消息
Description: Tells the server to allow a maximum of pending messages per client.
方法原型:WithMaxPendingMessagesPerClient(int value)
允许服务器保留会话
Description: Tells the server to persist sessions.
方法原型:WithPersistentSessions()
允许服务器使用存储
Description: Tells the server to use a storage.
方法原型:WithStorage(IMqttServerStorage value)
允许处理来自客户端的所有订阅
Description: Allows to work with all subscriptions from the clients.
方法原型:WithSubscriptionInterceptor(IMqttServerSubscriptionInterceptor value)
允许处理来自客户端的所有订阅
Description: Allows to work with all subscriptions from the clients.
方法原型:WithSubscriptionInterceptor(Action value)
禁用默认(非SSL)端口
Description: Disables the default (non SSL) endpoint.
方法原型:WithoutDefaultEndpoint()
禁用默认(SSL)端口
Description: Disables the default (SSL) endpoint.
方法原型:WithoutEncryptedEndpoint()