提供用户登陆以及维护用户的登陆状态,是一个拥有用户系统的软件应用广泛须要作的事情。像微信这样的一个社交平台,若是作一个小程序应用,咱们可能不多会去作一个彻底脱离和舍弃链接用户信息的纯工具软件。redis
让用户登陆,标识用户和获取用户信息,以用户为核心提供服务,是大部分小程序都会作的事情。咱们今天就来了解下在小程序中,如何作用户登陆,以及如何去维护这个登陆后的会话(Session)状态。json
在微信小程序中,咱们大体会涉及到如下三类登陆方式:小程序
第一和第二种方式是目前Web应用中最多见的两种方式,在微信小程序中一样可使用,可是须要值的注意的是,小程序中没有Cookie
的机制,因此在使用这2种方式前,请确认大家或第三方的API是否须要依赖Cookie
;还有小程序中也不支持HTML页面,那些须要使用页面重定向来进行登陆的第三方API就须要改造,或不能用了。微信小程序
咱们今天主要来讨论一下第三种方式,即如何使用微信帐号进行登陆,由于这种方式和微信平台结合最紧密,用户体验比较好。api
引用小程序官方文档的登陆流程图,整个登陆流程基本以下图所示:浏览器
登陆流程图安全
该图中,“小程序”指的就是咱们使用小程序框架写的代码部分,“第三方服务器”通常就是咱们本身的后台服务程序,“微信服务器”是微信官方的API服务器。服务器
下面咱们来逐步分解一下这个流程图。微信
登陆凭证(code)
在小程序中登陆的第一步,就是先获取登陆凭证。咱们可使用wx.login()方法并获得一个登陆凭证。cookie
咱们能够在小程序的App代码中发起登陆凭证请求,也能够在其余任何Page页面代码中发起登陆凭证请求,主要根据你小程序的实际须要。
App({ onLaunch: function() { wx.login({ success: function(res) { var code = res.code; if (code) { console.log('获取用户登陆凭证:' + code); } else { console.log('获取用户登陆态失败:' + res.errMsg); } } }); } })
惟一标识(openid)
和会话密钥(session_key)
首先,咱们使用wx.request()方法,请求咱们本身实现的一个后台API,并将登陆凭证(code)携带过去,例如在咱们前面代码的基础上增长:
App({ onLaunch: function() { wx.login({ success: function(res) { var code = res.code; if (code) { console.log('获取用户登陆凭证:' + code); // --------- 发送凭证 ------------------ wx.request({ url: 'https://www.my-domain.com/wx/onlogin', data: { code: code } }) // ------------------------------------ } else { console.log('获取用户登陆态失败:' + res.errMsg); } } }); } })
你的后台服务(/wx/onlogin)接着须要使用这个传递过来的登陆凭证,去调用微信接口换取openid和session_key,接口地址格式以下所示:
https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
这里是我使用了Node.js Express构建的后台服务的代码,仅供参考:
router.get('/wx/onlogin', function (req, res, next) { let code = req.query.code request.get({ uri: 'https://api.weixin.qq.com/sns/jscode2session', json: true, qs: { grant_type: 'authorization_code', appid: '你小程序的APPID', secret: '你小程序的SECRET', js_code: code } }, (err, response, data) => { if (response.statusCode === 200) { console.log("[openid]", data.openid) console.log("[session_key]", data.session_key) //TODO: 生成一个惟一字符串sessionid做为键,将openid和session_key做为值,存入redis,超时时间设置为2小时 //伪代码: redisStore.set(sessionid, openid + session_key, 7200) res.json({ sessionid: sessionid }) } else { console.log("[error]", err) res.json(err) } }) })
这段后台代码成功执行的话,就能够获得openid和session_key。这个信息就是当前微信帐户在微信服务器那边的登陆态了。
可是,为了安全方面的缘由,请不要直接使用这些信息做为你小程序的用户标识和session标识回传到小程序客户端中去,咱们应该在服务器端作一层本身的session,将这个微信帐号登陆态生成一个session id并维护在咱们本身的session机制中,而后把这个session id派发到小程序客户端做为session标识来使用。
关于如何在服务器端作这个session机制,咱们如今通常采用键值对存储工具来作,好比redis。咱们为每一个session生成一个惟一的字符串做为键,而后能够将session_key和openid做为值,存入redis中,为了安全,存入的时候还应设置一个超时的时间。
sessionid
开发Web应用的时候,在客户端(浏览器)中,咱们一般将session id存放在cookie中,可是小程序没有cookie机制,因此不能采用cookie了,可是小程序有本地的storage,因此咱们可使用storage来保存sessionid,以供后续的后台API调用所使用。
在以后,调用那些须要登陆后才有权限的访问的后台服务时,你能够将保存在storage中的sessionid取出并携带在请求中(能够放在header中携带,也能够放在querystring中,或是放在body中,根据你本身的须要来使用),传递到后台服务,后台代码中获取到该sessionid后,从redis中查找是否有该sessionid存在,存在的话,即确认该session是有效的,继续后续的代码执行,不然进行错误处理。
这是一个须要session验证的后台服务示例,个人sessionid是放在header中传递的,因此在这个示例中,是从请求的header中获取sessionid:
router.get('/wx/products/list', function (req, res, next) { let sessionid = req.header("sessionid") let sessionVal = redisStore.get(sessionid) if (sessionVal) { // 执行其余业务代码 } else { // 执行错误处理 } })
好了,经过微信帐号进行小程序登陆和状态维护的简单流程就是这样,了解这些知识点以后,再基于此进行后续的开发就会变得更容易了。
文章来源:http://www.jianshu.com/p/c5f6c98b2685
做者:一斤代码