小程序登陆态控制探索全过程

前段时间折腾过一下小程序,对登陆态控制进行了一些尝试和总结,此文以前在公众号进行过度享,回头看看,对目前也有必定的指导意义,因此在掘金旧文重发,但愿对掘友们有所帮助前端

1、微信建议的登陆态控制

图片来自微信
图片来自微信

说明:
1)小程序内经过wx.login接口得到code
2)将code传入后台,后台对微信服务器发起一个https请求换取openid、session_key
3)后台生成一个自身的3rd_session(以此为key值保持openid和session_key),返回给前端。PS:微信方的openid和session_key并无发回给前端小程序
4)小程序拿到3rd_session以后保持在本地
5)小程序请求登陆区内接口,经过wx.checkSession检查登陆态,若是失效从新走上述登陆流程,不然待上3rd_session到后台进行登陆验证 redis

2、可不能够不接受它的建议

不是我反骨,而是个人微信小程序不须要获取什么私密数据,用不到session_key,只须要一个openid,微信特别强调了,为了自身应用安全,session_key 不该该在网络上传输,可没说不能够传输openid,那么若是我将openid直接返回给前端小程序,会不会方便不少?下面咱们来具体分析下:数据库

永不过时的openid:
要知道,session_key有过时时间,必须适时从新获取,而针对每个小程序,惟一标识用户的openid可不会过时,若是只在用户第一次登陆的时候,经过后台请求到openid,小程序缓存到本地,以后每次请求都以这个openid做为惟一凭证,岂不是一本万利~~小程序

事实上,上面的作法忽略了一个致命的问题,手机上是能够切换微信帐户的,若是手机I上原先登陆了帐户A,已经保存了用户A的openid,有一天手机I上切换到了帐户B上,小程序检测到openid存在,并不会从新获取openid,那么帐户B就请求到了帐户A的数据,这就形成数据乱象了后端

登陆态过时后从新获取openid:
上述的问题并不能打消我使用openid做为登陆凭证的念头,只须要稍做改进,数据就不会乱窜:每次进入小程序经过wx.checkSession检测登陆是否失效,若是失效从新获取openid,要知道,手机切换了登陆帐号,登陆态必定会过时,这样虽不能一本万利,但也足够省心。微信小程序

这个时候应该有一个然而,以永不过时的openid做为登陆凭证,并非明智之举,一旦被人截获,就再也没有翻身的机会了,而维护一个第三发的session,至少拥有有效期,这在很大程度上增长了安全性。而且,如今不须要使用session_key,不表明之后,保持系统的可扩展性,才能以不变应万变缓存

事实证实,我仍是应该接受它的建议安全

3、基于redis维护3rd_session

维护3rd_session须要一个内存数据库,这里我选用了redisbash

维护会话态是内存数据库的典型应用场景,毕竟量小,而且要求速度快,这么一个小应用,固然也能够本身在内存中维护一个对象来进行会话id的处理,可是确定难以跟一个成熟的系统相媲美服务器

抛开代码实现,这彷佛就是一句话能够归纳的事情,生成一个惟一的随机串sessionid,以此为key,openid和微信方的session_key为value存入redis,并把sessionid传回给客户端。

可是,翻遍小程序的官方文档,除了一句听说的wx.checkSession对开发者来讲是透明的,并无小程序登陆态什么时候过时的具体说明,如何才能同步先后端的会话过时时间呢?

4、先后端会话过时时间同步

一开始,我仍是试图寻找小程序的登陆态时效

{"session_key":"...","expires_in":7200,"openid":"..."}复制代码

在code2session接口返回的数据中,有一个可疑的字段expires_in,它的值是7200,彷佛存储到redis中的sessionid设置为7200就能够同步了。但是实践的结果再次让人失望,不论是设置成7200仍是60*60*24(一天),都出现了小程序会话尚在有效期,而服务器端会话已通过期的状况,这直接致使了小程序带着已经缓存的sessionid到服务器端请求接口,返回未登陆的状况

看来仍是只有wx.checkSession才知道小程序会话啥时候过时,因而,做战方案从新作了调整,若是wx.checkSession检测到会话失效,那么带上已经缓存在本地的sessionid(若是有的话),从新发起登陆请求,后台从code2session中拿到新的请求结果后,生成新的随机sessionid并入库reids,而且把老的sessionid移除(若是有的话)

固然不移除也不会带来什么功能上的影响,可是会存在两个问题,首先,跟使用open_id做为登陆凭证同样,旧的sessionid永不过时,其次,无用的session数据占用redis资源,会拖垮访问性能

5、“脱贫致富指数”统计

我给小程序的用户数安了一个高大上的名字“脱贫致富指数”,纯属娱乐,切勿当真

为了统计使用小程序的用户数,须要一个表来保存用户数据,后台提供一个接口,让小程序将用户数据传上来进行一个注册操做,固然能够把这个功能合并到登陆接口上,每次登陆都把前端小程序得到的微信用户数据带上,若是发现数据库中尚未该用户的信息,则进行入库操做

不难发现,其实只须要用户第一次登陆的时候注册一次就好了,因此上述方法虽然简便,可是有点浪费带宽,因此应该额外提供一个注册接口,登陆接口只须要返回一个用户是否已经注册的标志,让客户端决定是否须要获取用户信息,进行注册操做(固然后台也不会让同一个用户重复入库)

那么问题就变成如何判断用户是第一次登陆了:
1)判断登陆请求中有没有带上sessionid,若是没带上,确定是第一次登陆;若是带上了就是登陆过的用户?不,别忘了,前面说过,用户可能会在同一设备切换帐户,那就有可能在登陆接口中带上了别人sessionid,那并不能代表用户曾经登陆过
2)经过带上来的sessionid从redis中拿到openid,跟在code2session新请求到的openid进行比对,若是一致,能够证实用户曾经登陆过,不然,仍须要用户进行注册

总结

时间是浪费了那么一些,可是进过思考摸索,代码确定更完备了~~

相关文章
相关标签/搜索