Python Paho MQTT客户端自签名证书的websockets,如何?

在Python中使用Paho与websockets和自签名证书进行https:// websocket连接有一些隐患,所以我在这里用一些示例代码解决这个问题。

输入ssl
进口时间
输入paho.mqtt.client作为mqtt

class PCPMQTTClient:
     def on_connect(self, client, userdata, flags, rc):
         self.connection_status = rc
         如果rc == 0。
             self.connected_flag = True
             self.connection_error_flag = False
         否则。
             self.connected_flag = False
             self.connection_error_flag = True

    当一个要用publish()发送的信息被调用时,#被调用。
     #已完成向经纪人的传输
     # for qos=0 -> 信息已离开客户端
     # for qos=1 & 2 -> 握手已经完成。
     #中间变量与publish()返回的中间变量相匹配。
     def on_publish(self, client, userdata, mid):
         如果self.verbose。
             print("publish callback mid:" + str(mid))

    def on_log(client, userdata, level, buf):
         print(buf)

    def testconnection(self):
         返回 self.connect(test=True)

    def connect(self, test=False):
         如果测试。
             print("Connecting to MQTT", end=")
         self.connection_status = -1 # 尚无连接尝试
         self.connection_error_flag = False
         self.mqttc.connect_async(
             host=self.connectiondata['host']。
             port=self.connectiondata['port']。
             keepalive=60。
             bind_address="")

        self.mqttc.loop_start() # 根据Steve的说法,最好是在连接之后。
         continue_flag = False
         keep_connection_flag = not test
         timeout_counter = 0
         而不是continue_flag。
             时间.睡眠(1)
             timeout_counter += 1
             如果测试。
                 print(".", end=") # end="将抑制换行。
             如果self.connected_flag。
                 continue_flag = True
             如果timeout_counter>6。
                 continue_flag = True
                 keep_connection_flag = False
         code = self.connection_status
         success = False
         如果代码==0。
             成功 = 真
             message = "连接成功!"
             self.connected_flag = True
             if not keep_connection_flag: #有必要这样做,以检测我们是否能够连接上!
                 self.disconnect() #干净地从服务器断开连接
         elif code == -1:
             message = "连接超时 - 服务器不在线?证书错误(尝试-selfsigned)?"
         elif code == 1:
             message = "连接拒绝 - 协议版本不正确"
         elif code == 2:
             message = "Connection refused - invalid client identifier"
         elif code == 3:
             message = "拒绝连接 - 服务器不可用"
         elif code == 4:
             message = "连接被拒绝 - 用户名或密码错误"
         elif code == 5:
             message = "连接被拒绝 - 未授权"
         否则。
             message = "另一个错误" + str(code) + " 发生了,请检查Paho文档"
         print(")
         返回 {"success": 成功, "code": 代码, "message": 消息}。

    def publish(self, topic, message, qos=0, retain=False):
         success = False
         code = 'PCP_WRONG_INPUTFORMAT' 。
         error_message = '错误的数据输入格式(例如,主题不能为空)' 。
         如果有话题。
             pubresult = self.mqttc.publish(
                 topic=topic,
                 payload=message。
                 qos=qos。
                 retain=retain)
             #进程公布结果
             如果pubresult.rc == mqtt.MQTT_ERR_SUCCESS。
                 code = 'MQTT_ERR_SUCCESS'。
                 error_message = 'Successfully sent message to broker.
                 成功 = 真
             elif pubresult.rc == mqtt.MQTT_ERR_NO_CONN:
                 code = 'MQTT_ERR_NO_CONN' 。
                 error_message = '没有连接到MQTT服务器,尝试重新连接' 。
             elif pubresult.rc == mqtt.MQTT_ERR_QUEUE_SIZE:
                 code = 'MQTT_ERR_QUEUE_SIZE' 。
                 error_message = '消息既没有排队,也没有发送。

        返回 {"success": 成功, "code": 代码, "message": 错误信息, "mid": pubresult.mid}.

    def disconnect(self):
         #按照Steve的说法 http://www.steves-internet-guide.com/client-connections-python-mqtt/
         self.mqttc.loop_stop()
         self.mqttc.disconnect()
         self.connected_flag = False

    def __init__(self, connectiondata, verbose=False, insecure=False):
         self.verbose = verbose
         clean_session = True
         self.mqttc = mqtt.Client(
             client_id=connectiondata['client_id']。
             clean_session=clean_session。
             userdata=None。
             protocol=mqtt.MQTTv311,
             transport=connectiondata['transport'])
         self.connectiondata = connectiondata
         self.connected_flag = False
         self.mqttc.on_connect = self.on_connect
         self.mqttc.on_publish = self.on_publish
         如果self.verbose。
             print("### enabling logging for MQTT Client ##")
             self.mqttc.on_log = self.on_log
         self.mqttc.username_pw_set(
             username=connectiondata['username']。
             password=connectiondata['password'])
         如果connectiondata['transport'] == "websockets"。
             self.mqttc.ws_set_options(path=self.connectiondata['path'] )
         如果self.verbose。
             print("###连接,参数如下 ###" )
             print("* client_id: " + connectiondata['client_id'] )
             print("* clean_session:" + str(clean_session))
             print("* transport: " + connectiondata['transport'] )
             print("* path: " + connectiondata['path'] )
             print("* username: " + connectiondata['username'] )
             print("*密码:(不显示!)")
         # self.mqttc.tls_set_context()。
         如果不安全。
             self.mqttc.tls_set(cert_reqs=ssl.CERT_NONE)
             如果self.verbose。
                 print("###不安全操作模式(-selfsigned)设置!#1T3T1T3T")
             self.mqttc.tls_insecure_set(True)
         否则。
             self.mqttc.tls_set()

正如你所看到的,对于不安全的连接,做两件事情是很重要的。

  • tls_set(cert_reqs=ssl.CERT_NONE)
  • tls_insecure_set(True)

tls_insecure_set(True)调用将允许你省略证书名称匹配。它仍然会尝试确保证书是 有效 按照证书链的规定!

因此,我想这是一个有点错误的名称。

上面显示的示例代码是picockpit-client的开发的一部分,用于 picockpit.com平台

Paho / Websockets

connectiondata['transport'] 在代码的其他地方设置。它可以是(一个字符串)"tcp "或 "websockets"。

如果你指定了websockets,你可以另外使用ws_set_options来设置一个路径,例如"/mqtt"。

            host=self.connectiondata['host']。
             port=self.connectiondata['port']。

主机是你的网络主机 - 没有http/https前缀。例如,对于本地开发,我使用 "picockpit.local"(通过envoy代理,见我其他文章)。

端口,在TLS/SSL连接的情况下,默认HTTPS端口为443。

为方便调试而提出的建议。

为了更好地进行调试,将异步连接代码切换到同步连接(替换connect_async)。

        self.mqttc.connect(
            host=self.connectiondata['host']。
            port=self.connectiondata['port']。
            keepalive=60。
            bind_address="")

参考文献。