概述
记录一个企业微信jssdk的使用,因为要用到图片上传、扫描二维码等工具。项目是uniapp开发的h5项目,fastadmin(thinkphp5)后端
先看官方文档
一、安装sdk
安装及使用按照官方文档的操作,安装完之后重启一下编辑器!
二、接口鉴权
接口鉴权有两种方式,一种是企业身份注册,一种是应用身份注册。
这里我选择了应用注册。
涉及到js-sdk签名算法,见下面的官方文档:
https://developer.work.weixin.qq.com/document/path/90506
如果已经实现了可以继续往下。这里展开说说怎么做(前端的童鞋可以先回避,这里依靠后端实现)。
对应的后端代码,但是我这里实测是签名无效的,不知道问题出现在哪里,最后选择 把ticket返回给前端,用官方的签名算法去计算签名。
/**
* 企业微信JS-SDK配置接口
*/
public function wwregister()
{
$url = $this->request->post('url');
if (!$url) {
$this->error('缺少URL参数');
}
try {
// 1. 获取access_token
$accessToken = $this->getAccessToken();
// 2. 获取企业级jsapi_ticket
$jsapiTicket = $this->getJsapiTicket($accessToken);
// 3. 获取应用级jsapi_ticket
$appJsapiTicket = $this->getAppJsapiTicket($this->app_id, $this->app_secret);
// 4. 生成企业签名和应用签名
$configSignature = $this->generateConfigSignature($jsapiTicket, $url);
$agentConfigSignature = $this->generateAgentConfigSignature($appJsapiTicket, $url);
// 5. 构建响应数据
$config = [
'corpId' => $this->corpid,
'agentId' => $this->app_id,
'jsApiList' => ['chooseImage', 'scanQRCode'],
'configSignature' => $configSignature,
'agentConfigSignature' => $agentConfigSignature,
'timestamp' => $configSignature['timestamp'],
'nonceStr' => $configSignature['nonceStr'],
'tk1'=>$jsapiTicket,
'tk2'=>$appJsapiTicket
];
$this->success('获取成功', $config);
} catch (Exception $e) {
$this->error('获取失败: ' . $e->getMessage());
}
}
/**
* 生成企业级签名
*/
private function generateConfigSignature($jsapiTicket, $url)
{
$timestamp = time();
$nonceStr = $this->createNonceStr();
// 拼接签名参数
$string = "jsapi_ticket={$jsapiTicket}&noncestr={$nonceStr}×tamp={$timestamp}&url={$url}";
// 计算SHA1签名
$signature = sha1($string);
return [
'timestamp' => $timestamp,
'nonceStr' => $nonceStr,
'signature' => $signature
];
}
/**
* 生成应用级签名
*/
private function generateAgentConfigSignature($appJsapiTicket, $url)
{
$timestamp = time();
$nonceStr = $this->createNonceStr();
// 拼接签名参数
$string = "jsapi_ticket={$appJsapiTicket}&noncestr={$nonceStr}×tamp={$timestamp}&url={$url}";
// 计算SHA1签名
$signature = sha1($string);
return [
'timestamp' => $timestamp,
'nonceStr' => $nonceStr,
'signature' => $signature
];
}
/**
* 获取应用jsapi_ticket
*/
private function getAppJsapiTicket($agentid,$appsecret)
{
// 从缓存获取或重新请求
$jsapiTicket = Cache::get($agentid.'wecom_appjsapi_ticket');
if (!$jsapiTicket) {
// 这里应该拿应用的accesstoken
$accessToken = getAppAccessToken($agentid,$appsecret);
// 跟获取企业jsapi_ticket的却别在与请求的url不一样
$url = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token={$accessToken}&type=agent_config";
$result = $this->httpGet($url);
$result = json_decode($result, true);
if (isset($result['ticket'])) {
$jsapiTicket = $result['ticket'];
Cache::set($agentid.'wecom_appjsapi_ticket', $jsapiTicket, 7100); // 提前100秒过期
} else {
throw new Exception('获取jsapi_ticket失败: ' . json_encode($result));
}
}
return $jsapiTicket;
}
// 获取应用的accesstoken
public function getAppAccessToken($agentid,$appsecret)
{
$token = Cache::get($agentid.'_wecom_access_token');
if (!$token) {
$config = get_addon_config('wecom');
$corpid = $this->corpid;
$corpsecret = $appsecret;
$url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$corpid}&corpsecret={$corpsecret}";
$result = $this->httpGet($url);
$result = json_decode($result, true);
if (isset($result['access_token'])) {
$accessToken = $result['access_token'];
Cache::set($agentid.'_wecom_access_token', $accessToken, 7100); // 提前100秒过期
} else {
throw new Exception('获取access_token失败: ' . json_encode($result));
}
}
return $token;
}
/**
* 获取access_token
*/
private function getAccessToken()
{
// 从缓存获取或重新请求
$accessToken = Cache::get('wecom_access_token');
if (!$accessToken) {
$corpid = $this->corpid;
$corpsecret = $this->corpsecret;
$url = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={$corpid}&corpsecret={$corpsecret}";
$result = $this->httpGet($url);
$result = json_decode($result, true);
if (isset($result['access_token'])) {
$accessToken = $result['access_token'];
Cache::set('wecom_access_token', $accessToken, 7100); // 提前100秒过期
} else {
throw new Exception('获取access_token失败: ' . json_encode($result));
}
}
return $accessToken;
}
回到前端,在页面中写方法
三、遇到的问题
1、项目调试使用微信开发者工具;
2、项目本地开发,会报错“invalid url domain”
打包线上之后正常,是否只能一边改一边打包上线测试呢~我也没搞清楚是否有解决办法,不然不大方便啊!!
项目上线后,可以成功拿到jssdk权限
3、invalid signature
上面已经提到过了,如果拿后端返回的签名是无效的(当然不排除我写的后端方法有问题~)
虽然官方文档给出排错的文档,但是对接的心好累,下回分解了~
四、接口的使用:选择图像
经过大费周章的前期准备,万事俱备,终于可以正常使用工具了,例如图像选择
// 选择图片
const chooseImage = () => {
if (images.value.length >= 5) {
uni.showToast({
title: '最多上传5张图片',
icon: 'none'
});
return;
}
ww.chooseImage({
count: 5 - images.value.length, // 最多可以选择的图片张数
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
success: (res : any) => {
// 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
const localIds = res.localIds;
// 上传图片到微信服务器并获取服务器ID
localIds.forEach((localId : string) => {
uploadImageToWechat(localId);
});
},
fail: (err : any) => {
console.error('选择图片失败', err);
uni.showToast({
title: '选择图片失败',
icon: 'none'
});
}
});
};
看到这个窗口,前期准备功夫全不费工夫,终于可以上传文件了。
但是这仅仅是开始~图片会上传到企微服务器,还得拉下来保存到自己的服务器。又可以另外写一篇文章叙述了。