305 lines
7.9 KiB
Markdown
305 lines
7.9 KiB
Markdown
|
|
# ThingsBoard MQTT 认证机制说明
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
ThingsBoard 支持两种 MQTT 认证方式,每种方式的使用场景不同。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 认证方式对比
|
|||
|
|
|
|||
|
|
| 认证方式 | 用户名 | 密码 | 使用场景 | 推荐度 |
|
|||
|
|
|---------|--------|------|---------|--------|
|
|||
|
|
| **Access Token** | Access Token 值 | 留空 | 设备认证(最常用) | ⭐⭐⭐⭐⭐ |
|
|||
|
|
| **MQTT Basic** | 自定义用户名 | 自定义密码 | 传统 MQTT 认证 | ⭐⭐⭐ |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 方式 1:Access Token 认证(推荐)
|
|||
|
|
|
|||
|
|
### 工作原理
|
|||
|
|
|
|||
|
|
- **用户名**:使用设备的 Access Token 作为 MQTT 用户名
|
|||
|
|
- **密码**:留空(不设置)
|
|||
|
|
- **设备标识**:每个设备有唯一的 Access Token
|
|||
|
|
|
|||
|
|
### 为什么每个设备需要不同的 Access Token?
|
|||
|
|
|
|||
|
|
1. **设备身份识别**
|
|||
|
|
- Access Token 是设备的唯一标识符
|
|||
|
|
- ThingsBoard 通过 Access Token 识别是哪个设备连接
|
|||
|
|
|
|||
|
|
2. **安全隔离**
|
|||
|
|
- 不同设备使用不同的 Token,避免设备间数据混淆
|
|||
|
|
- 如果某个设备 Token 泄露,不影响其他设备
|
|||
|
|
|
|||
|
|
3. **权限控制**
|
|||
|
|
- 每个设备只能访问自己的数据
|
|||
|
|
- Token 与设备 ID 绑定,自动关联设备权限
|
|||
|
|
|
|||
|
|
### 连接示例
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 使用 Access Token 连接
|
|||
|
|
mosquitto_pub -h localhost -p 1883 \
|
|||
|
|
-t "v1/devices/me/telemetry" \
|
|||
|
|
-u "ABC123DEF456GHI789J0" \
|
|||
|
|
-m '{"temperature":25,"humidity":60}'
|
|||
|
|
|
|||
|
|
# 注意:-u 后面是 Access Token,没有 -P 参数(密码留空)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Python 示例
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
import paho.mqtt.client as mqtt
|
|||
|
|
|
|||
|
|
# Access Token(从设备凭证中获取)
|
|||
|
|
ACCESS_TOKEN = "ABC123DEF456GHI789J0"
|
|||
|
|
|
|||
|
|
client = mqtt.Client()
|
|||
|
|
# 使用 Access Token 作为用户名
|
|||
|
|
client.username_pw_set(ACCESS_TOKEN) # 密码留空
|
|||
|
|
|
|||
|
|
client.connect("localhost", 1883, 60)
|
|||
|
|
client.publish("v1/devices/me/telemetry", '{"temperature":25}')
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 方式 2:MQTT Basic 认证(传统用户名密码)
|
|||
|
|
|
|||
|
|
### 工作原理
|
|||
|
|
|
|||
|
|
- **用户名**:自定义用户名
|
|||
|
|
- **密码**:自定义密码
|
|||
|
|
- **客户端 ID**:可选的客户端 ID
|
|||
|
|
|
|||
|
|
### 配置步骤
|
|||
|
|
|
|||
|
|
1. **在 ThingsBoard Web UI 中配置**
|
|||
|
|
- 进入设备管理 → 选择设备
|
|||
|
|
- 点击 "Manage Credentials"
|
|||
|
|
- 选择凭证类型:**MQTT Basic**
|
|||
|
|
- 填写:
|
|||
|
|
- Client ID(可选)
|
|||
|
|
- User Name(用户名)
|
|||
|
|
- Password(密码)
|
|||
|
|
|
|||
|
|
2. **连接示例**
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 使用 MQTT Basic 认证连接
|
|||
|
|
mosquitto_pub -h localhost -p 1883 \
|
|||
|
|
-i "my-client-id" \
|
|||
|
|
-t "v1/devices/me/telemetry" \
|
|||
|
|
-u "my-username" \
|
|||
|
|
-P "my-password" \
|
|||
|
|
-m '{"temperature":25,"humidity":60}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Python 示例
|
|||
|
|
|
|||
|
|
```python
|
|||
|
|
import paho.mqtt.client as mqtt
|
|||
|
|
|
|||
|
|
# MQTT Basic 认证信息
|
|||
|
|
CLIENT_ID = "my-client-id" # 可选
|
|||
|
|
USERNAME = "my-username"
|
|||
|
|
PASSWORD = "my-password"
|
|||
|
|
|
|||
|
|
client = mqtt.Client(client_id=CLIENT_ID)
|
|||
|
|
client.username_pw_set(USERNAME, PASSWORD)
|
|||
|
|
|
|||
|
|
client.connect("localhost", 1883, 60)
|
|||
|
|
client.publish("v1/devices/me/telemetry", '{"temperature":25}')
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 源码分析
|
|||
|
|
|
|||
|
|
### Access Token 认证流程
|
|||
|
|
|
|||
|
|
**位置**:`common/transport/mqtt/src/main/java/org/thingsboard/server/transport/mqtt/MqttTransportHandler.java`
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
private void processAuthTokenConnect(ChannelHandlerContext ctx, MqttConnectMessage connectMessage) {
|
|||
|
|
String userName = connectMessage.payload().userName(); // Access Token 作为用户名
|
|||
|
|
// 如果密码为空,使用 Access Token 认证
|
|||
|
|
// 如果密码不为空,使用 MQTT Basic 认证
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**认证逻辑**:`application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java`
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
private TransportApiResponseMsg validateUserNameCredentials(...) {
|
|||
|
|
DeviceCredentials credentials = deviceCredentialsService.findDeviceCredentialsByCredentialsId(mqtt.getUserName());
|
|||
|
|
if (credentials != null) {
|
|||
|
|
switch (credentials.getCredentialsType()) {
|
|||
|
|
case ACCESS_TOKEN:
|
|||
|
|
// Access Token 认证:用户名就是 Access Token
|
|||
|
|
return getDeviceInfo(credentials);
|
|||
|
|
case MQTT_BASIC:
|
|||
|
|
// MQTT Basic 认证:需要验证用户名和密码
|
|||
|
|
if (VALID.equals(validateMqttCredentials(mqtt, credentials))) {
|
|||
|
|
return getDeviceInfo(credentials);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 认证判断逻辑
|
|||
|
|
|
|||
|
|
ThingsBoard 如何判断使用哪种认证方式?
|
|||
|
|
|
|||
|
|
1. **如果 MQTT 连接时密码为空**:
|
|||
|
|
- 将用户名当作 Access Token 查找设备凭证
|
|||
|
|
- 如果找到且类型是 `ACCESS_TOKEN`,认证成功
|
|||
|
|
|
|||
|
|
2. **如果 MQTT 连接时提供了密码**:
|
|||
|
|
- 先尝试 Access Token 认证(用户名作为 Token)
|
|||
|
|
- 如果失败,尝试 MQTT Basic 认证(验证用户名+密码)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 实际使用建议
|
|||
|
|
|
|||
|
|
### 推荐使用 Access Token(原因)
|
|||
|
|
|
|||
|
|
1. **简单易用**
|
|||
|
|
- 只需要一个 Token,不需要管理密码
|
|||
|
|
- 设备端配置简单
|
|||
|
|
|
|||
|
|
2. **安全性**
|
|||
|
|
- Token 可以随时重新生成
|
|||
|
|
- 每个设备独立 Token,隔离性好
|
|||
|
|
|
|||
|
|
3. **ThingsBoard 设计**
|
|||
|
|
- 这是 ThingsBoard 的主要认证方式
|
|||
|
|
- 所有文档和示例都基于 Access Token
|
|||
|
|
|
|||
|
|
### 使用 MQTT Basic 的场景
|
|||
|
|
|
|||
|
|
1. **需要兼容现有 MQTT 系统**
|
|||
|
|
- 如果设备已经使用用户名密码认证
|
|||
|
|
- 需要与标准 MQTT Broker 兼容
|
|||
|
|
|
|||
|
|
2. **集中管理认证信息**
|
|||
|
|
- 可以使用统一的用户名密码策略
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 常见问题
|
|||
|
|
|
|||
|
|
### Q1: 为什么不能所有设备用同一个 Access Token?
|
|||
|
|
|
|||
|
|
**答**:
|
|||
|
|
- 每个设备需要独立的身份标识
|
|||
|
|
- 如果多个设备用同一个 Token,ThingsBoard 无法区分是哪个设备
|
|||
|
|
- 数据会混乱,无法正确关联到设备
|
|||
|
|
|
|||
|
|
### Q2: Access Token 和传统 MQTT 用户名密码有什么区别?
|
|||
|
|
|
|||
|
|
| 特性 | Access Token | MQTT Basic |
|
|||
|
|
|------|-------------|------------|
|
|||
|
|
| 数量 | 每个设备一个 | 可以多个设备共享 |
|
|||
|
|
| 密码 | 不需要 | 需要 |
|
|||
|
|
| 管理 | ThingsBoard 自动生成 | 手动配置 |
|
|||
|
|
| 安全性 | 高(唯一标识) | 中(可能共享) |
|
|||
|
|
|
|||
|
|
### Q3: 如何查看设备的 Access Token?
|
|||
|
|
|
|||
|
|
**方法 1:Web UI**
|
|||
|
|
```
|
|||
|
|
Devices → 选择设备 → Manage Credentials → 查看 Access Token
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**方法 2:REST API**
|
|||
|
|
```bash
|
|||
|
|
curl -X GET "http://localhost:8080/api/device/{deviceId}/credentials" \
|
|||
|
|
-H "X-Authorization: Bearer $JWT_TOKEN"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Q4: 可以在同一个设备上使用两种认证方式吗?
|
|||
|
|
|
|||
|
|
**答**:不可以。每个设备只能配置一种认证方式:
|
|||
|
|
- 要么使用 Access Token
|
|||
|
|
- 要么使用 MQTT Basic
|
|||
|
|
- 不能同时使用
|
|||
|
|
|
|||
|
|
### Q5: 如何切换认证方式?
|
|||
|
|
|
|||
|
|
1. 进入设备管理 → 选择设备
|
|||
|
|
2. 点击 "Manage Credentials"
|
|||
|
|
3. 选择新的凭证类型
|
|||
|
|
4. 配置相应的凭证信息
|
|||
|
|
5. 保存
|
|||
|
|
|
|||
|
|
**注意**:切换后,旧凭证立即失效,设备需要重新连接。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 完整示例对比
|
|||
|
|
|
|||
|
|
### 示例 1:Access Token 认证
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 设备 A(Access Token: TOKEN_A)
|
|||
|
|
mosquitto_pub -h localhost -p 1883 \
|
|||
|
|
-t "v1/devices/me/telemetry" \
|
|||
|
|
-u "TOKEN_A" \
|
|||
|
|
-m '{"temperature":25}'
|
|||
|
|
|
|||
|
|
# 设备 B(Access Token: TOKEN_B)
|
|||
|
|
mosquitto_pub -h localhost -p 1883 \
|
|||
|
|
-t "v1/devices/me/telemetry" \
|
|||
|
|
-u "TOKEN_B" \
|
|||
|
|
-m '{"temperature":30}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 示例 2:MQTT Basic 认证
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 设备 A(用户名: device-a, 密码: pass123)
|
|||
|
|
mosquitto_pub -h localhost -p 1883 \
|
|||
|
|
-t "v1/devices/me/telemetry" \
|
|||
|
|
-u "device-a" \
|
|||
|
|
-P "pass123" \
|
|||
|
|
-m '{"temperature":25}'
|
|||
|
|
|
|||
|
|
# 设备 B(用户名: device-b, 密码: pass456)
|
|||
|
|
mosquitto_pub -h localhost -p 1883 \
|
|||
|
|
-t "v1/devices/me/telemetry" \
|
|||
|
|
-u "device-b" \
|
|||
|
|
-P "pass456" \
|
|||
|
|
-m '{"temperature":30}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 总结
|
|||
|
|
|
|||
|
|
1. **Access Token 认证**(推荐)
|
|||
|
|
- 每个设备有唯一的 Access Token
|
|||
|
|
- 使用 Access Token 作为 MQTT 用户名,密码留空
|
|||
|
|
- 简单、安全、易管理
|
|||
|
|
|
|||
|
|
2. **MQTT Basic 认证**
|
|||
|
|
- 使用传统的用户名+密码
|
|||
|
|
- 适合需要兼容现有 MQTT 系统的场景
|
|||
|
|
|
|||
|
|
3. **选择建议**
|
|||
|
|
- **新项目**:使用 Access Token
|
|||
|
|
- **已有系统**:根据需求选择,如需兼容标准 MQTT,使用 MQTT Basic
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 相关文档
|
|||
|
|
|
|||
|
|
- [ThingsBoard MQTT API 文档](https://thingsboard.io/docs/reference/mqtt-api/)
|
|||
|
|
- [设备凭证管理文档](https://thingsboard.io/docs/user-guide/device-credentials/)
|
|||
|
|
|