uniCloud开发公众号:六、解析不同情况下用户扫码后微信推送的事件并完成登录

算是个系列内容吧,最终要实现的是将uniCloud作为后端完成“扫码关注公众号后完成网站登录”
将要涉及的内容可能包括:
0.准备工作(本节)
1.接受并解析xml消息
2.请求access_token并缓存
3.生成带参数二维码
4.引入、封装redis缓存方法
5.开通、配置、初始化uniPush2.0
6.解析不同情况下用户扫码时推送的事件并完成登录

系列内容全部基于uniCloud+vk-uniCloud(云函数路由)+uni-app
编辑器HbuilderX最新版
云空间为阿里云
公众号为认证服务号

好了,终于来到最后也是最重要的一节,这节将把前边全部的内容串起来,最终完成一开始说的扫公众号二维码关注公众号完成网站登录
其实这个流程已经烂大街了,但基于uniCloud来搞,应该还没有人分享过。

一、梳理用户扫码后的事件
官方文档说,未关注的用户扫码后关注,推过来的事件是subscribe,这个确实没错,
已关注用户扫码后,实际上是直接进入聊天界面的,这时候推送过来的事件是SCAN,没错,它是大写的……

二、编写统一入口文件代码
这样,我们就知道,在第零节我们那个index.js入口中,就可以这么写:

// 先把接收到的xml解析出来,详见第一节
let {
	ToUserName, // appid
	FromUserName, // openid
	MsgType, // text,event
	EventKey,
} = xmlObj;
// 然后
if(MsgType == 'event'){
	let Event = xmlObj.Event;
	// 这里来处理逻辑,见下边那大段代码
	if(Event == 'SCAN'){
		// 已关注用户扫码
	}else if(Event == 'subscribe'){
		// 未关注用户扫码、且完成关注
	}
}

三、完成后端创建用户、token等
这里我把逻辑处理的部分单独拿出来,否则会比较乱

// 判断用户是否存在
let uniUserInfo = await vk.baseDao.findByWhereJson({
	dbName: "uni-id-users",
	whereJson: {
		'wxUserInfo.openid': FromUserName // 扫码用户的openid
	}
});

// 查询redisData
// 这里注意一下,存储到redis时,我们写了一个随机数
// 但如果是已关注用户扫码进来时,EventKey是不包含qrscene_的,需要手动拼上去
let EventKey = EventKey.indexOf('qrscene_') !== -1 ? EventKey : 'qrscene_' + EventKey;
// 这里就用上我们第四节封装的方法,来获取创建二维码时缓存到redis的数据
let redisData = await pubFun.getRedisData(EventKey);

// 直接删除redis
// 这里直接清掉,防止被其他用户重复扫码
pubFun.delRedisData(EventKey);

if (vk.pubfn.isNull(redisData )) {
	// 没查到redis,说明要么真过期了,要么是被其他用户扫过了
	// 这种情况就直接返回一条消息给用户
	// 这里用到了第一节中拼装xml消息的方法
	msgContent = await pubFun.createXmlTextMsg(FromUserName, '二维码已过期,请刷新~');
	res.body = msgContent;
	return res;
} else {
	// 查询到了redis缓存
	// 继续判断是否存在这个用户
	// 不存在,则直接在服务端创建一个用户
	let uid;
	if (vk.pubfn.isNull(uniUserInfo)) {
		let currentTime = new Date().getTime();
		// 随机生成用户名
		let username = 'user_' + vk.pubfn.random(
			6,
			"abcdefghijklmnopqrstuvwxyz0123456789"
		);
		// 随机生成6位密码
		let password = vk.pubfn.random(6); 

		// 创建用户
		let addUserRes = await uniID.addUser({
			username,
			password,
			authorizedApp: [redisData.clientAppid] // 这里必须给一个,否则无法登录
		});
		
		// 新建了用户,赋值
		uid = addUserRes.uid;

		// 获取微信unionId
		// 这个方法之前没说,放到最后来说
		let wxUserInfo = await pubFun.getWxUserInfoByToken(FromUserName);

		// 用户其他信息
		let dataJson = {
			wxUserInfo,
			status: 0,
		};
		// 追加用户其他信息
		await vk.baseDao.update({
			dbName: 'uni-id-users',
			whereJson: {
				_id: uid
			},
			dataJson
		});
	
		// 这样就完成了一个用户的创建
		uniUserInfo = addUserRes;
	} else {
		// 如果用户已经存在,则直接赋值uid即可
		uid = uniUserInfo._id;
	}
	
	// 但这时候我们不能把usernam和password返回前端,因为密码是加密过的
	// 所以需要生成token并返回
	let tokenRes = await uniID.createToken({
		uid
	});
	
	// 比较奇怪的时候,这个token在生成后,并不会被自动追加到用户表,需要手动追加一下。
	// 追加token
	await vk.baseDao.update({
		dbName: 'uni-id-users',
		whereJson: {
			_id: uid
		},
		dataJson: {
			token: [tokenRes.token] // 我这里比较粗暴的直接替换掉了
		}
	});

	// 上边一通操作,实际上就是为了在后端完成用户的创建、登录
	// 通过uniPush推送给客户端扫码成功的消息
	await uniPush.sendMessage({
		"push_clientid": redisData.pushClientid, // 这是我们在创建二维码时缓存下来的值
		"title": "扫码成功",
		"content": "感谢关注,现在进入登录环节",
		"payload": {
			type: 'login', // 登录消息
			tokenRes, // 把token返回给前端
			userInfo: uniUserInfo // 用户资料也一起返回
		}
	})
}

这样,我们回头看上一段代码,就可以这么改:

if(MsgType == 'event'){
	let Event = xmlObj.Event;
	// 这里写上边那一大段逻辑
	if(Event == 'SCAN'){
		// 已关注用户扫码
		msgContent = '登录成功,欢迎回来~';
	}else if(Event == 'subscribe'){
		// 未关注用户扫码、且完成关注
		msgContent = '感谢关注,登陆成功~';
	}
}
// 在公众号中也提醒一下用户
msg= await pubFun.createXmlTextMsg(FromUserName,msgContent );
res.body = msgContent;
return res;

文案不同,大概就是下边这种意思。
uniCloud开发公众号:六、解析不同情况下用户扫码后微信推送的事件并完成登录_第1张图片

四、前端接受推送消息,完成登录
回到前端,我们在第五节有说过如何监听uniPush的消息。

uni.onPushMessage(res => {
// 这里因为我们只是web端,所以获取的内容实际上是透传的内容,也就是payload字段的内容
let payload = res.data.payload;
if (payload.type == 'barrage') {
	// 我其他的处理
} else if (payload.type == 'login') {
	// 先把接收到的userInfo缓存下来
	vk.vuex.set('$user.userInfo', payload.userInfo);
	// 然后注意,token和tokenExpired两个字段,需要用官方的方法去缓存到localStorage
	uni.setStorageSync('uni_id_token', payload.tokenRes.token);
	uni.setStorageSync('uni_id_token_expired', payload.tokenRes.tokenExpired);
	// 缓存完之后,用vk的方法检查一下是否可用
	if (!vk.checkToken()) {
		vk.toast('登录失败,请重试');
		return;
	}
	// 如果可用,则刷新页面完成登录
	// 页面上我也是用vuex来判断是否登录成功的,刷新是为了关闭那个popup
	vk.toast('登录成功', 'success', 1500, true, () => {
		vk.reLaunch('/pages/index/index');
	});
}
});

到这里,所有的环节就都完成了,我们再来回顾一下逻辑。

用户前端点击微信登录

前端发起生成二维码并传参pushClientId和appid,

后端接收后先请求access_token

然后创建带参数二维码返回ticket、同时把数据缓存到redis

前端接收到ticket后拼接成图片地址并显示,

用户使用微信扫码

未关注用户关注后,后端接收到微信推送的subscribe事件

根据openid和scene查询redis,

后端创建用户token

根据redis的数据,将用户资料和token数据通过uniPush推送前端

前端监听到之后完成登录

最后的最后,看一下我实际的效果:额,好像不支持上传视频,那就自行体验吧。

https://neverbug.cn

你可能感兴趣的:(公众号,unicloud,前端,微信,javascript,开发语言)