# 修复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无效!🔐