微信小程序登录态控制深入分析
最近微信小程序终于开放了个人注册,我当然不能浪费这个炫技的好机会,“菲麦日程”小程序正在全力推进中,尽请期待~~
在登录态控制中,摸索尝试了小一阵子,特此分享
一、微信建议的登录态控制
说明:
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到后台进行登录验证
二、可不可以不接受它的建议
不是我反骨,而是我的微信小程序不需要获取什么私密数据,用不到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,不代表以后,保持系统的可扩展性,才能以不变应万变
事实证明,我还是应该接受它的建议
三、基于redis维护3rd_session
维护3rd_session需要一个内存数据库,这里我选用了redis
维护会话态是内存数据库的典型应用场景,毕竟量小,并且要求速度快,这么一个小应用,当然也可以自己在内存中维护一个对象来进行会话id的处理,但是肯定难以跟一个成熟的系统相媲美
抛开代码实现,这似乎就是一句话可以概括的事情,生成一个唯一的随机串sessionid,以此为key,openid和微信方的session_key为value存入redis,并把sessionid传回给客户端。
但是,翻遍小程序的官方文档,除了一句据说的wx.checkSession对开发者来说是透明的,并没有小程序登录态何时过期的具体说明,如何才能同步前后端的会话过期时间呢?
四、前后端会话过期时间同步
一开始,我还是试图寻找小程序的登录态时效
{"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移除(如果有的话)