新增功能

This commit is contained in:
Your Name
2026-03-04 15:32:30 +08:00
parent a07e844c47
commit ab77f5488d
2266 changed files with 177942 additions and 3444 deletions
+299
View File
@@ -0,0 +1,299 @@
# 修复UserSig生成算法错误
## 🔍 问题发现
通过对比腾讯云官方生成的UserSig和我们系统生成的UserSig,发现格式完全不同:
### 腾讯云官方生成(正确)✅
```
eJwtjEEPwTAYQP9Lz7J8rXWdJS4OhMwFw1yW0q4*zWimGSH*u5kd33vJe5NNug4aXZOEsADIoGNU*uqxxE476bHFYtjHu7LSOVQkoREAZUJQ*Bf9dFjr1nPOGUBvPVY-JwQLGfBw1F-QtO9Jtrsd1OlcHe28iS*wTOXCZrGSj9K*ZF6uoi2fTWFvTD4mny8uFDNl
```
- 格式:gzip压缩 + Base64 URL安全编码
- 特点:包含 `*``-` 字符
- 长度:约150-200字符
### 我们系统生成(错误)❌
```
eyJUTFMuc2lnIjoiVmRNRDdcL2IyMTF1MHpDSjFuNkc1aFNxNitnMm5rdm11Mkh1WnRyZVwvYTI0PSIsIlRMUy52ZXIiOiIyLjAiLCJUTFMuaWRlbnRpZmllciI6InBhdGllbnRfNCIsIlRMUy5zZGthcHBpZCI6MTYwMDEyNzcxMCwiVExTLmV4cGlyZSI6MTU1NTIwMDAsIlRMUy50aW1lIjoxNzcyNDE4MTcyfQ==
```
- 格式:仅Base64编码,**缺少gzip压缩**
- 特点:以 `==` 结尾,标准Base64
- 长度:约250-300字符
解码后是纯JSON
```json
{
"TLS.sig": "VdMD7/b211u0zCJ1n6G5hSq6+g2nkvmu2HuZtre/a24=",
"TLS.ver": "2.0",
"TLS.identifier": "patient_4",
"TLS.sdkappid": 1600127710,
"TLS.expire": 15552000,
"TLS.time": 1772418172
}
```
## ❌ 问题根源
`DiagnosisLogic.php` 中,`generateUserSig()` 方法使用了**自定义的错误实现**,而不是官方的 `TLSSigAPIv2` 类。
### 错误的实现
```php
// ❌ 错误:缺少gzip压缩步骤
private static function generateUserSig(...)
{
$sigDoc = [
'TLS.ver' => '2.0',
'TLS.identifier' => $userId,
// ...
];
$base64Doc = base64_encode(json_encode($sigDoc));
$signature = hash_hmac('sha256', $base64Doc, $secretKey, true);
$userSig = [
'TLS.sig' => base64_encode($signature),
// ...
];
return base64_encode(json_encode($userSig)); // ❌ 缺少gzip压缩
}
```
### 正确的流程
腾讯云官方算法:
```
1. 构建签名内容
2. HMAC-SHA256签名
3. 构建完整的JSON文档
4. gzip压缩 ⭐ 关键步骤
5. Base64 URL安全编码
6. 返回UserSig
```
我们的错误实现:
```
1. 构建签名内容
2. HMAC-SHA256签名
3. 构建完整的JSON文档
4. Base64编码 ❌ 缺少gzip压缩
5. 返回UserSig
```
## ✅ 解决方案
使用官方的 `TLSSigAPIv2` 类,它已经实现了正确的算法。
### 修改前
```php
private static function generateUserSig(int $sdkAppId, string $secretKey, string $userId, int $expire = 86400)
{
try {
$current = time();
$sigDoc = [
'TLS.ver' => '2.0',
'TLS.identifier' => $userId,
'TLS.sdkappid' => $sdkAppId,
'TLS.expire' => $expire,
'TLS.time' => $current
];
$base64Doc = base64_encode(json_encode($sigDoc));
$signature = hash_hmac('sha256', $base64Doc, $secretKey, true);
$base64Signature = base64_encode($signature);
$userSig = [
'TLS.sig' => $base64Signature,
'TLS.ver' => '2.0',
'TLS.identifier' => $userId,
'TLS.sdkappid' => $sdkAppId,
'TLS.expire' => $expire,
'TLS.time' => $current
];
return base64_encode(json_encode($userSig)); // ❌ 错误
} catch (\Exception $e) {
return false;
}
}
```
### 修改后
```php
private static function generateUserSig(int $sdkAppId, string $secretKey, string $userId, int $expire = 86400)
{
try {
// ✅ 使用官方的TLSSigAPIv2类
$api = new \app\common\service\TLSSigAPIv2($sdkAppId, $secretKey);
$userSig = $api->genUserSig($userId, $expire);
return $userSig;
} catch (\Exception $e) {
\think\facade\Log::error('生成UserSig失败: ' . $e->getMessage());
return false;
}
}
```
## 📝 TLSSigAPIv2 的正确实现
官方类的关键代码:
```php
private function __genSig($identifier, $expire, $userbuf, $userbuf_enabled)
{
$current = time();
$sigDoc = [
'TLS.ver' => '2.0',
'TLS.identifier' => strval($identifier),
'TLS.sdkappid' => intval($this->sdkappid),
'TLS.expire' => intval($expire),
'TLS.time' => intval($current)
];
// 生成签名
$sig = $this->hmacsha256($identifier, $current, $expire, $base64_userbuf, $userbuf_enabled);
$sigDoc['TLS.sig'] = base64_encode($sig);
// 转JSON
$json_text = json_encode($sigDoc);
// ⭐ 关键:gzip压缩
$compressed = gzcompress($json_text);
// ⭐ 关键:URL安全的Base64编码
return $this->base64_url_encode($compressed);
}
// URL安全的Base64编码
private function base64_url_encode($input)
{
return str_replace(['+', '/', '='], ['*', '-', '_'], base64_encode($input));
}
```
## 🎯 影响范围
这个修复会影响所有生成UserSig的地方:
1. **医生通话签名** - `getCallSignature()`
2. **患者通话签名** - `getPatientSignature()`
3. **患者账号创建** - `createPatientTrtcAccount()`
所有这些方法都调用 `generateUserSig()`,现在都会使用正确的算法。
## 🧪 测试方法
### 1. 清除旧数据
```sql
-- 清除旧的患者TRTC账号(UserSig格式错误)
TRUNCATE TABLE zyt_tcm_patient_trtc;
```
### 2. 重新生成UserSig
```bash
# 方式A:通过新增诊单
# 进入诊单管理 > 新增诊单 > 保存
# 方式B:运行测试脚本
cd server
php test_usersig.php
```
### 3. 验证格式
查看数据库中的UserSig
```sql
SELECT user_id, user_sig FROM zyt_tcm_patient_trtc ORDER BY id DESC LIMIT 1;
```
**正确的格式**应该类似:
```
eJwtjEEPwTAYQP9Lz7J8rXWdJS4OhMwFw1yW0q4*zWimGSH*...
```
**错误的格式**(旧数据):
```
eyJUTFMuc2lnIjoiVmRNRDdcL2IyMTF1MHpDSjFuNkc1aFNxNitnMm5r...
```
### 4. 测试通话
1. 进入诊单详情
2. 点击"视频通话"
3. 应该能成功初始化,不再报 -1201 错误
## 📊 对比总结
| 项目 | 错误实现 | 正确实现 |
|------|---------|---------|
| 算法来源 | 自定义 | 腾讯云官方 |
| gzip压缩 | ❌ 无 | ✅ 有 |
| Base64编码 | 标准 | URL安全 |
| UserSig长度 | 250-300字符 | 150-200字符 |
| 格式特征 | 以`==`结尾 | 包含`*``-` |
| 能否登录IM | ❌ 失败 | ✅ 成功 |
## 🔍 为什么之前没发现?
1. **测试不充分**:只测试了UserSig生成,没有测试IM登录
2. **错误提示不明确**:-1201错误只说"初始化未完成",没说UserSig无效
3. **格式看起来正常**:都是Base64编码,不仔细对比看不出问题
## ⚠️ 重要提醒
### 需要清除旧数据
数据库中已存在的患者TRTC账号使用的是错误格式的UserSig,需要:
1. **方案A:清空表**(推荐)
```sql
TRUNCATE TABLE zyt_tcm_patient_trtc;
```
2. **方案B:删除旧记录**
```sql
DELETE FROM zyt_tcm_patient_trtc WHERE create_time < UNIX_TIMESTAMP();
```
3. **方案C:让系统自动更新**
- 编辑诊单时会自动重新生成
- 但旧的UserSig仍然无效
### 不影响新数据
修复后新生成的UserSig都是正确格式,可以正常使用。
## 📚 相关文档
- [TLSSigAPIv2.php](./server/app/common/service/TLSSigAPIv2.php) - 官方算法实现
- [腾讯云UserSig生成文档](https://cloud.tencent.com/document/product/269/32688)
- [DIAGNOSE_INIT_FAIL.md](./DIAGNOSE_INIT_FAIL.md) - 初始化失败诊断
## 更新日志
### 2026-03-02
- ✅ 发现UserSig生成算法错误
- ✅ 修改为使用官方TLSSigAPIv2类
- ✅ 添加gzip压缩步骤
- ✅ 使用URL安全的Base64编码
- ✅ 清理重复代码
---
**关键要点**:必须使用官方的TLSSigAPIv2类,自定义实现会缺少gzip压缩导致UserSig无效!🔐