Files
zyt/FIX_USERSIG_ALGORITHM.md
T
2026-03-04 15:32:30 +08:00

300 lines
7.6 KiB
Markdown
Raw 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.
# 修复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无效!🔐