个人网站微信扫码登陆.小程序码登陆.免关注(三)
文章目录
扫小程序码登陆网站方案的 .web服务器部分代码和逻辑.
总体就是四步骤.
1,生成一个二维码.
2,等待扫码登陆,微信小程序返回结果.
3,解密微信小程序结果,获取并记录用户信息,
4,web用户登陆.
生成带参数二维码
我用的是overtrue/wechat包
init
$wxinfo['app_id'] = 'appid';
$wxinfo['secret'] ='secret';
$this->miniapp =Factory::miniProgram($wxinfo);
二维码
echo $this->miniapp->app_code->getUnlimit($request_str);
exit;
直接用echo输出,因为返回的图片HTTP流,而不是一个图片链接.
输出后结束函数.
$request_str 就是你要生成的参数.这个是写入数据库的.
微信小程序扫码后会得到这个值.
登陆轮询
这个无非就是判断$request_str有没有被使用,自己加一个标记比如isUse字段. 当微信小程序扫码后,更新这个字段.
轮询的时候不过就是循环判断这个值是否更新了.是一个比较简单的操作.
小程序对接
参数
我有个对外的api接口,专门给小程序登陆提交过来的.
public function pushCode(String $code,String $scene ,String $iv ,String $encryptedData){
//....
}
需要接收的参数就是上面4个.
$scene就是之前$request_str的
判断
在解码之前,
得判断下参数是否存在.
$scene是否存在,或者是否过期.
获取session_key
session_key就是解密用户信息用的密钥.
需要调用微信小程序API获取.
我自己将code用个数据库缓存了起来,如果不存起来,短时间,连续扫码会解密失败..
如果code没有记录,那么调用
$this->miniapp->auth->session($code);
获取解密用的session_key,
如果有记录那么直接数据库拿.
//看看code缓存
$minicodeinfo = Minicode::where(['code'=>$code])->find();
if (empty($minicodeinfo)){
try {
$res = $this->miniapp->auth->session($code);
$session_key = $res['session_key'] ;
} catch (Exception $e){
throw new Exception('小程序code过期,考虑清小程序缓存.');
}
}else{
$session_key = $minicodeinfo -> session_key;
}
解密用户信息
if (!empty($session_key)){
try {
$rrs = @$this->miniapp->encryptor->decryptData($session_key, $iv, $encryptedData);
} catch (Exception $e) {
throw new Exception('小程序异常,考虑清小程序缓存.');
}
//...........
else{
//return $this->error(-191,'解密错误,考虑清空小程序缓存.','微信错误信息: ' . $res['errmsg']);
}
直接调用接口即可.
$rrs就是解密后的用户信息
内容就是
{
"openId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"nickName": "Y.A.K.E",
"gender": 1,
"language": "zh_CN",
"city": "Xinyu",
"province": "Jiangxi",
"country": "China",
"avatarUrl": "https://wx.qlogo.cn/mmopen/vi_32/WWCC67raM9t3A05kuyjmR3tXlLor4DQkFwmSBY3icN0YYjPtZudf2mBsVv1C5CGkaAibjKBDBicOysRP1nFqtgjrA/132",
"unionId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"watermark": {
"timestamp": 1543412981,
"appid": "wx8a18e3c3091991ef"
}
openId 就是用户 对当前小程序唯一ID
unionId 就是用户对 你微信开发平台账号(主体) 唯一ID.
unionId 必须要在微信小程序绑定开发者平台的情况下才能获取到.前面说过,这是一个免费的操作.
新增或者更新用户信息
$allow_field = array('nickName','openId','gender','language','city','province','country','avatarUrl');
User::update($vrrs, ['unionId' => $rrs['unionId']],$allow_field);
我的主键是id,和unionId.
更新或者新建都是最基本的数据库操作.
判断登陆
也就是给数据写入一个登陆标记.
通过$request_str判断.
写入一个isUse标记.同时将用户ID写入二维码记录表.
那么前台轮询就会判断已经登陆.
自动登陆
自动登陆是轮询的时候同时干的事.
$qr_info = Qr::where('request_str',$request_str)->find();
然后判断isUse字段是否更新了.
更新了同时应该还有userId .
拿到userId后,然后开始写出cookie到浏览器就完成了登陆了.
补充和注意事项
二维码
小程序调用接口生成临时二维码有调用次数限制.
微信小程序规定每分钟调用生成临时二维码接口不能超过5000次.
超过限制,接口调用失败.直到下一分钟恢复.
按次算的. 也就是说,相同参数,一次请求就算一次,多次请求,就算多次.
如果有人恶意刷新我二维码页面,每分钟刷新5000次.那么我博客二维码就会因为接口调用次数超过限制.就会用不了.
如果接口调用次数不想浪费,那么还可以缓存二维码图片到服务器.
我没去缓存,换了一个比较懒的方案.
生成的二维码有效期建议拉长一些.
我博客是30分钟.也就是生成二维码之后,会在30分钟轮询是否登陆.超过30分钟才算超时.
多小程序联合
也就是unionid概念.
我准备了两个个备用小程序.
小程序内容随便弄的.没啥功能.
完全是备胎.随时准备切换的.
做好了博客授权登陆.
暂时没有启用.
其他一样
唯一不同点. 就是每个用户,不同小程序openid不同.
绑定同一个开发者平台账号,unionid是相同的.
听起来有点不太明白.
小程序A | 小程序B | |||
用户 | openid | unionid | openid | unionid |
张三 | O1 | U1 | OX1 | U1 |
李四 | O2 | U2 | OX2 | U2 |
王五 | O3 | U3 | OX3 | U3 |
张三,在不同微信小程序,微信公众号,的openid都不相同.
张三,在不同微信小程序,微信公众号的unionid都相同.
unionid相同,是有主体的概念.
一个开发者(微信开放平台)账号是一个主体 .
小程序A和小程序B必须绑定在同一个开发者(微信开放平台)账号.
才会使得张三在小程序A和B中的unionid值相同.
如果小程序A解绑了原来的开发者(微信开放平台)账号
而绑定到了其他的开发者(微信开放平台)账号.
那么张三的unionid也会变更.