thingsboard/summary/23-ThingsBoard-MQTT认证机制说明.md

305 lines
7.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ThingsBoard MQTT 认证机制说明
## 概述
ThingsBoard 支持两种 MQTT 认证方式,每种方式的使用场景不同。
---
## 认证方式对比
| 认证方式 | 用户名 | 密码 | 使用场景 | 推荐度 |
|---------|--------|------|---------|--------|
| **Access Token** | Access Token 值 | 留空 | 设备认证(最常用) | ⭐⭐⭐⭐⭐ |
| **MQTT Basic** | 自定义用户名 | 自定义密码 | 传统 MQTT 认证 | ⭐⭐⭐ |
---
## 方式 1Access 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}')
```
---
## 方式 2MQTT 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
**答**
- 每个设备需要独立的身份标识
- 如果多个设备用同一个 TokenThingsBoard 无法区分是哪个设备
- 数据会混乱,无法正确关联到设备
### Q2: Access Token 和传统 MQTT 用户名密码有什么区别?
| 特性 | Access Token | MQTT Basic |
|------|-------------|------------|
| 数量 | 每个设备一个 | 可以多个设备共享 |
| 密码 | 不需要 | 需要 |
| 管理 | ThingsBoard 自动生成 | 手动配置 |
| 安全性 | 高(唯一标识) | 中(可能共享) |
### Q3: 如何查看设备的 Access Token
**方法 1Web UI**
```
Devices → 选择设备 → Manage Credentials → 查看 Access Token
```
**方法 2REST 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. 保存
**注意**:切换后,旧凭证立即失效,设备需要重新连接。
---
## 完整示例对比
### 示例 1Access Token 认证
```bash
# 设备 AAccess Token: TOKEN_A
mosquitto_pub -h localhost -p 1883 \
-t "v1/devices/me/telemetry" \
-u "TOKEN_A" \
-m '{"temperature":25}'
# 设备 BAccess Token: TOKEN_B
mosquitto_pub -h localhost -p 1883 \
-t "v1/devices/me/telemetry" \
-u "TOKEN_B" \
-m '{"temperature":30}'
```
### 示例 2MQTT 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/)