7.6 KiB
7.6 KiB
修复UserSig生成算法错误
🔍 问题发现
通过对比腾讯云官方生成的UserSig和我们系统生成的UserSig,发现格式完全不同:
腾讯云官方生成(正确)✅
eJwtjEEPwTAYQP9Lz7J8rXWdJS4OhMwFw1yW0q4*zWimGSH*u5kd33vJe5NNug4aXZOEsADIoGNU*uqxxE476bHFYtjHu7LSOVQkoREAZUJQ*Bf9dFjr1nPOGUBvPVY-JwQLGfBw1F-QtO9Jtrsd1OlcHe28iS*wTOXCZrGSj9K*ZF6uoi2fTWFvTD4mny8uFDNl
- 格式:gzip压缩 + Base64 URL安全编码
- 特点:包含
*和-字符 - 长度:约150-200字符
我们系统生成(错误)❌
eyJUTFMuc2lnIjoiVmRNRDdcL2IyMTF1MHpDSjFuNkc1aFNxNitnMm5rdm11Mkh1WnRyZVwvYTI0PSIsIlRMUy52ZXIiOiIyLjAiLCJUTFMuaWRlbnRpZmllciI6InBhdGllbnRfNCIsIlRMUy5zZGthcHBpZCI6MTYwMDEyNzcxMCwiVExTLmV4cGlyZSI6MTU1NTIwMDAsIlRMUy50aW1lIjoxNzcyNDE4MTcyfQ==
- 格式:仅Base64编码,缺少gzip压缩
- 特点:以
==结尾,标准Base64 - 长度:约250-300字符
解码后是纯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 类。
错误的实现
// ❌ 错误:缺少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 类,它已经实现了正确的算法。
修改前
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;
}
}
修改后
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 的正确实现
官方类的关键代码:
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的地方:
- 医生通话签名 -
getCallSignature() - 患者通话签名 -
getPatientSignature() - 患者账号创建 -
createPatientTrtcAccount()
所有这些方法都调用 generateUserSig(),现在都会使用正确的算法。
🧪 测试方法
1. 清除旧数据
-- 清除旧的患者TRTC账号(UserSig格式错误)
TRUNCATE TABLE zyt_tcm_patient_trtc;
2. 重新生成UserSig
# 方式A:通过新增诊单
# 进入诊单管理 > 新增诊单 > 保存
# 方式B:运行测试脚本
cd server
php test_usersig.php
3. 验证格式
查看数据库中的UserSig:
SELECT user_id, user_sig FROM zyt_tcm_patient_trtc ORDER BY id DESC LIMIT 1;
正确的格式应该类似:
eJwtjEEPwTAYQP9Lz7J8rXWdJS4OhMwFw1yW0q4*zWimGSH*...
错误的格式(旧数据):
eyJUTFMuc2lnIjoiVmRNRDdcL2IyMTF1MHpDSjFuNkc1aFNxNitnMm5r...
4. 测试通话
- 进入诊单详情
- 点击"视频通话"
- 应该能成功初始化,不再报 -1201 错误
📊 对比总结
| 项目 | 错误实现 | 正确实现 |
|---|---|---|
| 算法来源 | 自定义 | 腾讯云官方 |
| gzip压缩 | ❌ 无 | ✅ 有 |
| Base64编码 | 标准 | URL安全 |
| UserSig长度 | 250-300字符 | 150-200字符 |
| 格式特征 | 以==结尾 |
包含*和- |
| 能否登录IM | ❌ 失败 | ✅ 成功 |
🔍 为什么之前没发现?
- 测试不充分:只测试了UserSig生成,没有测试IM登录
- 错误提示不明确:-1201错误只说"初始化未完成",没说UserSig无效
- 格式看起来正常:都是Base64编码,不仔细对比看不出问题
⚠️ 重要提醒
需要清除旧数据
数据库中已存在的患者TRTC账号使用的是错误格式的UserSig,需要:
-
方案A:清空表(推荐)
TRUNCATE TABLE zyt_tcm_patient_trtc; -
方案B:删除旧记录
DELETE FROM zyt_tcm_patient_trtc WHERE create_time < UNIX_TIMESTAMP(); -
方案C:让系统自动更新
- 编辑诊单时会自动重新生成
- 但旧的UserSig仍然无效
不影响新数据
修复后新生成的UserSig都是正确格式,可以正常使用。
📚 相关文档
- TLSSigAPIv2.php - 官方算法实现
- 腾讯云UserSig生成文档
- DIAGNOSE_INIT_FAIL.md - 初始化失败诊断
更新日志
2026-03-02
- ✅ 发现UserSig生成算法错误
- ✅ 修改为使用官方TLSSigAPIv2类
- ✅ 添加gzip压缩步骤
- ✅ 使用URL安全的Base64编码
- ✅ 清理重复代码
关键要点:必须使用官方的TLSSigAPIv2类,自定义实现会缺少gzip压缩导致UserSig无效!🔐