微信小程序 接口调用讲解 (AccessToken小程序码登录)
Posted moTzxx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信小程序 接口调用讲解 (AccessToken小程序码登录)相关的知识,希望对你有一定的参考价值。
☞ 前言
- 当前对于网站项目的开发,针对于客户使用的 小程序是最为主要的
在此整理几个使用频率高的接口
方便开发人员的后期参考,以及对功能的快速实现
☞ 重要分享接口 梳理
下面,整理出实际业务中,使用频率较高的接口,做下分享
▷ 1 登录信息获取
-
【场景描述】
当用户在我们开发的小程序中,点击授权登录时
我们可以通过微信官方提供的登录能力,方便地获取用户 身份标识,
从而将微信用户与我们的产品数据进行绑定,快速建立起小程序内的用户体系
之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份
- 登录流程时序如下:
简而言之,我们要获取微信用户的唯一标识
OpenID
,关联自己的业务
♦ 接口描述
-
【请求地址】:
【GET】 https://api.weixin.qq.com/sns/jscode2session
-
【请求参数 】
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
appid | 是 | string | 小程序唯一凭证,即 AppID,可在「微信公众平台 - 设置 - 开发设置」页面获得 |
secret | 是 | string | 小程序唯一凭证密钥,即 AppSecret,获取方式同 appid |
js_code | 是 | string | 登录时获取的 code (小程序端通过 wx.login 接口获得临时登录凭证 code) |
grant_type | 是 | string | 授权类型,此处只需填写 authorization_code |
- 【返回参数】
参数名 | 类型 | 说明 |
---|---|---|
openid | string | 用户唯一标识 |
session_key | string | 会话密钥 session_key 是对用户数据进行 加密签名 的密钥 |
unionid | string | 用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台帐号下会返回 |
errcode | string | 错误码: -1 、0 、40029 、 45011 、 40226 (具体说明,请阅读 接口文档) |
errmsg | string | 错误信息 |
♦ 示例代码
- 【php 示例代码】
(😦 tip: 公共方法do_curl_get_request()
可见附录)
$url = 'https://api.weixin.qq.com/sns/jscode2session';
$param = [
'appid' => 'xxxxxxx',
'secret' => 'xxxxxxxxxxxxxxxx',
'js_code' => 'CODE',// 小程序端通过 wx.login 接口获得临时登录凭证 code
'grant_type' => 'authorization_code',
];
$res = do_curl_get_request($url,$param);
♦ [提示]
- 小程序登录成功后,将登录信息(
openid、session_key
)保存下来
即,保存登录令牌Token,方便用户登录状态的维持
在接下来的获取接口,有令牌就可以 访问,没有的话就不能访问
- 对于为什么要换取 Token,如何使用 Token,可以参考下面的两篇文章:
- 如果,需要获取微信用户的 昵称,地址、微信头像等信息
可以参考接口 —— 开放数据校验与解密 进行有效信息的获取
接口如果涉及敏感数据(如wx.getUserInfo当中的 openId 和 unionId), 需要对接口返回的加密数据(
encryptedData
) 进行对称解密
- 最终解密获得的 json 数据如下:
"openId": "OPENID",
"nickName": "NICKNAME",
"gender": GENDER,
"city": "CITY",
"province": "PROVINCE",
"country": "COUNTRY",
"avatarUrl": "AVATARURL",
"unionId": "UNIONID",
"watermark":
"appid":"APPID",
"timestamp":TIMESTAMP
一般用于,对新注册微信用户的绑定记录,方便我们在自己网站业务中的用户识别操作!
▷ 2 接口调用凭证 AccessToken
-
【场景描述】
首先,要明确一点
此处提到的access_token
,是 作为 小程序 全局唯一 后台接口调用凭据
而对于服务端的接口来说
绝大部分的服务,都需要使用access_token
,开发者需要进行妥善保存
♦ 接口描述
-
【请求地址】:
【GET】 https://api.weixin.qq.com/cgi-bin/token
-
【请求参数 】
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
grant_type | 是 | string | 填写 "client_credential" |
appid | 是 | string | 小程序唯一凭证,即 AppID,可在「微信公众平台 - 设置 - 开发设置」页面获得 |
secret | 是 | string | 小程序唯一凭证密钥,即 AppSecret,获取方式同 appid |
正常时返回:
"access_token":"ACCESS_TOKEN","expires_in":7200
错误时返回:
"errcode":40013,"errmsg":"invalid appid"
♦ 示例代码
- 【PHP 示例代码】
(😦 tip: 公共方法do_curl_get_request()
可见附录)
$url = 'https://api.weixin.qq.com/cgi-bin/token';
$param = [
'grant_type' => 'client_credential',
'appid' => 'wxexxxxxxxx',
'secret' => 'f6eebxxxxxxxxxxxxxxxxxxxxx'
];
//返回数据,自行提取保存
$res = do_curl_get_request($url,$param);
♦ [提示]
-
access_token
的有效期目前为 2 个小时,
需定时刷新,重复获取将导致上次获取的access_token
失效所以,注意:不要在测试环境随意调用,影响生产环境的业务使用,实际场景中,可以考虑直接使用线上环境获取的
"access_token"
【经验建议】
对于上面提到的,测试环境 影响 生产环境 业务使用的问题: 首先,要将 access_token 操作的业务,提取到一个公共方法中,方便逻辑代码的统一控制 其次,在此方法中, 应补充检测 access_token 是否失效的逻辑 如果失效,要及时获取 最新的有效 access_token // —— 分析发现,需要对所有使用到 access_token 的接口,做容错处理 (不现实) 或者,可以考虑,测试环境与生产环境 统一取用 中控服务器中的 access_token // —— 分析发现,如果开发人员无意中自主请求凭证,那么依然是无法保证线上 凭证的同步 最后,注意到,其实官方给出了建议, —— 如果使用了云托管或云开发,可以免维护 access_token,免鉴权直接调用服务端接口
-
access_token
的保存使用
在实际开发中,大多数的服务接口都会用到这个 凭证
每次使用时,没必要重新获取
那么可以考虑使用redis
进行存储(注意:设定有效时长不超过7200秒)
如果没有
redis
,也可存储在mysql
数据表,服务器session
、甚至file
文件中,只要保证读取时间有效即可 !
▷ 3 小程序码 登录
-
【场景描述】
以实际开发场景为例:
为了便于商家登录PC端,将原来的 短信验证码登录 替换为 微信小程序码 扫码登录
商家扫码后,微信端会跳入小程序页面,
同时,PC端会自动进入网站,简化登录流程,提高用户体验 -
整体流程演示图:
♦ 接口描述
-
请求地址:
【POST】 https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
-
【请求参数 】
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
access_token | 是 | string | 接口调用凭证 |
scene | 是 | string | 场景信息,最大32个可见字符,只支持数字,大小写英文以及部分特殊字符 以我的代码实现为例,设定的字符串为: pc_code=$pc_code |
page | 否 | string | 页面 page,例如 pages/index/index ,根路径前不要填加 /,不能携带参数(参数请放在scene字段里),如果不填写这个字段,默认跳主页面 |
注:对于参数
scene
,其中的pc_code
值,可以在 PC 端请求小程序码时,随机生成,可用时间戳+随机数,后续的逻辑中,会以此pc_code
判断哪个码扫码登录成功
- 【开发思路】
1. 用户在 PC 端请求显示 小程序码时,需要一个传一个参数 pc_code (可用时间戳+随机数)
2. 后台,curl 调用微信服务接口,获取小程序码,返回到 PC 端显示
3. 后台将这个 pc_code,进行 redis 存储,状态 status 设定为 未登录状态
$value = ['status'=>0,'create_time' => time()];
$redis->hSetNx($cache_key_pc_scan_mini_code,$pc_code)
4. 如果,小程序检测到登录,
要更新 redis, 状态 status 设定为 已登录状态
5. PC端,设定一个轮询 js (条件允许的话,可以考虑使用 websocket)
每秒查看 status 是否失效、已登录
如果失效(5分钟),要重新获取新的 小程序码,或引导用户刷新页面
如果登录成功,根据返回的 用户Token,进行登录后业务处理
6. 设计一个计划任务,处理已过时的 小程序码,做好交互
♦ 示例代码
- 生成 小程序码
/**
* 获取不受限制的小程序二维码
* @param $page string 页面路径
* @param $scene string 携带参数
* @param $width int 宽度
* @param $color array 颜色
* @param $isHyaline boolean 是否透明底色
* @return string
*
* @throws Exception
*/
public function unlimitedAcode(string $scene, string $page='', int $width=50, array $color=[], bool $isHyaline=false)
$url = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit';
$query = [
'access_token' => $this->accessToken()
];
$data = [
'scene' => $scene,
'width' => $width,
'auto_color' => $color ? false : true,
'is_hyaline' => $isHyaline
];
if ($page)
$data['page'] = $page;
if (!$data['auto_color'])
$data['line_color'] = [
'r' => $color[0],
'g' => $color[1],
'b' => $color[2]
];
$client = new Client([
'query' => $query,
'body' => json_encode($data)
]);
$res = $client->post($url);
return $res->getBody()->getContents();
- 更新 商家PC端 小程序码状态信息
/**
* 更新 商家PC端 小程序码状态信息
* @param int $opTag 1:获取小程序码;2:检测小程序码,扫码状态;3:商家小程序端,登录后的缓存更新
* @param string $pc_code PC端,标识码
* @param string $scan_open_id $opTag=3 时,需要传参
* @return array
*/
public static function opCacheKeyScanMiniCode($opTag = 1,$pc_code = '',$scan_open_id = '')
$cache_key_pc_scan_mini_code = config('mz.pc_scan_mini_code');
$redis = redis();
if($opTag === 1)
//获取小程序码后,进行 redis 存储
$value = ['status'=>0,'create_time' => time()];
$redis->hSetNx($cache_key_pc_scan_mini_code,$pc_code,json_encode($value,JSON_UNESCAPED_UNICODE));
elseif ($opTag === 2)
//此时为,获取小程序码 状态信息
$scanVal = $redis->hget($cache_key_pc_scan_mini_code,$pc_code);
$scan_open_id = '';
if ($scanVal)
$arr_scanVal = json_decode($scanVal,true);
$scan_status =$arr_scanVal['status']??0;
if ($scan_status == 0)
//判断是否已过期
$create_time =$arr_scanVal['create_time']??0;
if ((time()-$create_time)> 300)
//暂定 5分钟后 失效 (小程序码已过期)
$scan_status = 2;
//TODO 可设计一个计划任务,剔除已超时的键
else
$scan_open_id =$arr_scanVal['open_id']??'';
else
//为了前端显示的判断,也设定为 失效
$scan_status = 2;
return [$scan_status,$scan_open_id];
elseif ($opTag === 3)
//此时,小程序端,登录成功后,更新用户信息
$scanVal = $redis->hget($cache_key_pc_scan_mini_code,$pc_code);
if ($scanVal)
$arr_scanVal = json_decode($scanVal,true);
$arr_scanVal['status'] = 1;
$arr_scanVal['open_id'] = $scan_open_id;
$redis->hSet($cache_key_pc_scan_mini_code,$pc_code,json_encode($arr_scanVal,JSON_UNESCAPED_UNICODE));
/**
* //TODO 考虑,去除已登录、超时的键
* 去除 超时的键
*/
public static function updateCacheKeyScanMiniCode()
$cache_key_pc_scan_mini_code = config('mz.pc_scan_mini_code');
$redis = redis();
$list = $redis->hGetAll($cache_key_pc_scan_mini_code);
foreach ($list as $key => $val)
$arr_cache_val = json_decode($val,true)??[];
$create_time = $arr_cache_val['create_time']??0;
if ((time() - $create_time) > 300)
//此为 设定超时的键 5分钟
$redis->hDel($cache_key_pc_scan_mini_code,$key);
return [true,'PC端登录小程序码,更新成功'];
- 接口返回
"code": 200,
"msg": "小程序码获取成功!",
"data":
"mini_code": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD..."
♦ [提示]
- ① 小程序码登录优势
1. 使用小程序码登录,用户真正登录行为发生在小程序上,同步给网页的是登录态,
相比于微信二维码登录同步给网页临时 code,
然后在重定向到业务登录后台换取登录态方式,
小程序码方式少了一次请求,带来更佳用户体验
2. 整体登录流程,UI更可控,也便于登录问题定位
- ②
【经验建议】
对于前面提到的pc_code
值的设定建议
对于 pc_code 值,如果使用了 “时间戳+随机数”:
实际上,很可能会被恶意人员暴力破解,简单的就猜到了我们的实现逻辑,从而截取数据,分析出我们网站的登录数据
此时,可以考虑:
对这里的 pc_code 值做加密操作,
—— 设计加密逻辑,每隔一段时间加密参数变动即可,避免恶意破解
- ③.
【经验建议】
对于页面使用 js 轮询获取 小程序码扫码状态的建议
相对来说,设计为简单的 js 轮询方式
无疑是对 资源请求的一种浪费,虽然接口中的代码逻辑耗时可忽略
但,难免遇到恶意份子的 暴力请求情况
首先,一种最简单的优化方式:
—— 轮询时间缩短,比如一分钟,如此一来直接在用户行为上,降低了无效请求
其次,可以考虑比较常用的 websocket 长链接方式:
—— 将原来的被动请求,变为主动触发,减少资源的请求浪费 (听起来就高大上一些)
参考文章:
♘ 通过微信小程序实现扫码登录
♘【网页版】使用小程序码登录
♘ 通过扫小程序码实现网站登录功能
☞ 附录
- 公共方法
/**
* CURL-get请求
* @param string $url 请求的url
* @param array $param 请求的参数
* @param string $output 输出格式
* @param int $timeout 超时时间
* @return mixed 数组形式
*/
function do_curl_get_request($url = '', $param = [],$output = 'json', $timeout = 10)
$ch = curl_init();
if (is_array($param))
$url = $url . '?' . http_build_query($param);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // 允许 cURL 函数执行的最长秒数
$data = curl_exec($ch);
curl_close($ch);
if ($output == 'json')
$json = json_decode($data , true);
return $json ?? $data ;
else
return $data ;
/**
* CURL-post请求
* @param string $url 请求的url地址
* @param array $param 请求的参数
* @param array $header
* @param string $output 输出格式
* @param int $timeout 超时时间
* @return mixed
*/
function do_curl_post_request($url = '', $param = [], $header = [], $output = 'json',$timeout = 10)
$ch = curl_init();
if (is_array($param))
$urlparam = http_build_query($param);
else if (is_string($param)) //json字符串
$urlparam = $param;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); //设置超时时间
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //返回原生的(Raw)输出
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_POST, 1); //POST
curl_setopt($ch, CURLOPT_POSTFIELDS, $urlparam); //post数据
if ($header)
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
$data = curl_exec($ch);
curl_close($ch);
if ($output == 'json')
$json = json_decode($data , true);
return $json ?? $data ;
else
return $data ;
微信小程序如何调用后台接口
参考技术A 本课程讲解了微信小程序如何调用线上API中心接口,主要使用了wx.request去和API中心交互,API中心提供给了下面的几个接口:
接口是用JFinal开发封装 @jfinal 用key-value形式存取数据。
以上是关于微信小程序 接口调用讲解 (AccessToken小程序码登录)的主要内容,如果未能解决你的问题,请参考以下文章