jsapi
This commit is contained in:
@@ -609,4 +609,139 @@ HTML;
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取飞书 JS API 鉴权签名
|
||||
* 用于前端初始化飞书 JS SDK
|
||||
*
|
||||
* company 参数可选,如果未提供则从登录 token 中获取用户所属公司
|
||||
*/
|
||||
public function feishuJsapiSignature(Request $request): Response
|
||||
{
|
||||
$url = $request->get('url');
|
||||
$companyParam = $request->get('company');
|
||||
|
||||
if (!$url) {
|
||||
return $this->error('缺少 url 参数');
|
||||
}
|
||||
|
||||
try {
|
||||
$companyId = null;
|
||||
|
||||
// 优先使用传入的 company 参数
|
||||
if ($companyParam) {
|
||||
$company = \app\model\Company::find($companyParam);
|
||||
if (!$company) {
|
||||
return $this->error('公司不存在');
|
||||
}
|
||||
$companyId = $company->id;
|
||||
error_log("✅ 使用参数中的 company: {$companyId}");
|
||||
}
|
||||
// 从 token 中获取用户所属公司
|
||||
else {
|
||||
$companyId = $this->getCompanyId($request);
|
||||
if (!$companyId) {
|
||||
return $this->error('未登录且未指定公司', 401);
|
||||
}
|
||||
error_log("✅ 从 token 获取 company: {$companyId}");
|
||||
}
|
||||
|
||||
// 获取该公司的默认飞书应用
|
||||
$feishuApp = \app\model\CompanyFeishuApp::where('company_id', $companyId)
|
||||
->where('system_id', 1)
|
||||
->where('status', 1)
|
||||
->first();
|
||||
|
||||
if (!$feishuApp) {
|
||||
return $this->error('该公司未配置飞书应用');
|
||||
}
|
||||
|
||||
// 生成 JS API 签名
|
||||
$signatureData = $this->generateJsapiSignature($feishuApp->id, $url);
|
||||
|
||||
return $this->success([
|
||||
'app_id' => $feishuApp->app_id,
|
||||
'company_id' => $companyId,
|
||||
'jsapi_ticket' => $signatureData['jsapi_ticket'],
|
||||
'noncestr' => $signatureData['noncestr'],
|
||||
'timestamp' => $signatureData['timestamp'],
|
||||
'url' => $signatureData['url'],
|
||||
'signature' => $signatureData['signature'],
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
error_log("❌ feishuJsapiSignature 失败: " . $e->getMessage());
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 JS API 鉴权签名
|
||||
*
|
||||
* @param int $feishuAppId 飞书应用配置ID
|
||||
* @param string $url 当前页面URL
|
||||
* @return array 签名数据
|
||||
*/
|
||||
private function generateJsapiSignature(int $feishuAppId, string $url): array
|
||||
{
|
||||
// 获取 jsapi_ticket
|
||||
$jsapiTicket = \app\util\FeishuUtil::getJsapiTicket($feishuAppId);
|
||||
|
||||
// 清理 URL:移除 # 和 ? 后面的参数
|
||||
$url = $this->cleanUrl($url);
|
||||
|
||||
// 生成随机字符串
|
||||
$noncestr = $this->generateNonceStr();
|
||||
|
||||
// 获取毫秒级时间戳
|
||||
$timestamp = (int)round(microtime(true) * 1000);
|
||||
|
||||
// 拼接签名字符串
|
||||
$verifyStr = "jsapi_ticket={$jsapiTicket}&noncestr={$noncestr}×tamp={$timestamp}&url={$url}";
|
||||
|
||||
// 生成 SHA1 签名
|
||||
$signature = sha1($verifyStr);
|
||||
|
||||
error_log("✅ JS API 签名生成成功: url={$url}");
|
||||
|
||||
return [
|
||||
'jsapi_ticket' => $jsapiTicket,
|
||||
'noncestr' => $noncestr,
|
||||
'timestamp' => $timestamp,
|
||||
'url' => $url,
|
||||
'signature' => $signature,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理 URL,移除 # 和 ? 后面的参数
|
||||
*/
|
||||
private function cleanUrl(string $url): string
|
||||
{
|
||||
// 移除 # 后面的内容
|
||||
$pos = strpos($url, '#');
|
||||
if ($pos !== false) {
|
||||
$url = substr($url, 0, $pos);
|
||||
}
|
||||
|
||||
// 移除 ? 后面的内容
|
||||
$pos = strpos($url, '?');
|
||||
if ($pos !== false) {
|
||||
$url = substr($url, 0, $pos);
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成随机字符串(由数字、字母组成)
|
||||
*/
|
||||
private function generateNonceStr(int $length = 16): string
|
||||
{
|
||||
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
$noncestr = '';
|
||||
for ($i = 0; $i < $length; $i++) {
|
||||
$noncestr .= $chars[mt_rand(0, strlen($chars) - 1)];
|
||||
}
|
||||
return $noncestr;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user