[TOC]
## 3.4 微信登录
微信登录的整个过程,如图4-22所示。
![微信登录的整个过程](../../images/3_1532854760668.JPG)
:-: 图4-22 微信登录的整个过程
### 3.4.1 获取微信登录凭证code
wx.login是生成一个带有时效性的凭证,就像是一个会过期的临时身份证一样,在wx.login调用时,会先在微信后台生成一张临时的身份证,其有效时间仅为5分钟 ` ??.hy[界面图] `。然后把这个临时身份证返回给小程序方,这个临时的身份证我们把它称为微信登录凭证code。
由于这个临时身份证5分钟后会过期,如果黑客要冒充一个用户的话,那他就必须在5分钟内穷举所有的身份证id,然后去开发者服务器换取真实的用户身份。显然,黑客要付出非常大的成本才能获取到一个用户信息,同时,开发者服务器也可以通过一些技术手段检测到5分钟内频繁从某个ip发送过来的登录请求,从而拒绝掉这些请求。
### 3.4.2 发送code到开发者服务器
在wx.login的success回调中拿到微信登录凭证,紧接着会通过wx.request把code传到开发者服务器,为了后续可以换取微信用户身份id(注意id不是指微信用户的微信号/密码等隐私信息,可以理解为id是微信用户在服务器的一个编号)。如果当前微信用户还没有绑定当前小程序业务的用户身份,那在这次请求应该顺便把用户输入的帐号密码(是用户在业务侧的帐号密码,而不是其微信的帐号密码)一起传到后台,然后开发者服务器就可以校验账号密码之后再和微信用户id进行绑定,小程序端的示例代码如下所示。
代码清单4-12 wx.login获取code后
~~~
Page({
tapLogin: function() {
wx.login({
success: function(res) {
if (res.code) {
wx.request({
url: 'https://test.com/login',
data: {
username: 'zhangsan', // 用户输入的账号
password: 'pwd123456', // 用户输入的密码
code: res.code
},
success: function(res) {
// 登录成功
if (res.statusCode === 200) {
console.log(res.data.sessionId)// 服务器回包内容
}
}
})
} else {
console.log('获取用户登录态失败!' + res.errMsg)
}
}
});
}
})
~~~
### 3.4.3 到微信服务器换取微信用户身份id
到了这一步,开发者的后台就拿到了前边wx.login()所生成的微信登录凭证code,此时就可以拿这个code到微信服务器换取微信用户身份。
微信服务器为了确保拿code过来换取身份信息的人就是刚刚对应的小程序开发者,到微信服务器的请求要同时带上AppId和AppSecret,这两个信息在小程序管理平台的开发设置界面(小程序管理平台地址`https://mp.weixin.qq.com`)可以看到。由此可以看出,AppId和AppSecret是微信鉴别开发者身份的重要信息:
`AppId`是公开信息,泄露AppId不会带来安全风险,但是`AppSecret`是开发者的隐私数据不应该泄露,如果发现泄露需要到小程序管理平台进行重置AppSecret,而code在成功换取一次信息之后也会立即失效,即便凭证code生成时间还没过期。
开发者服务器和微信服务器通信也是通过HTTPS协议,微信服务器提供的接口地址是:
`https://api.weixin.qq.com/sns/jscode2session?appid=<AppId>&secret=<AppSecret>&js_code=<code>&grant_type=authorization_code`
URL的query部分的参数中 \<AppId>, \<AppSecret>, \<code> 就是前文所提到的三个信息,请求参数合法的话,接口会返回以下字段。
:-: 表4-3 jscode2session接口返回字段
| 字段 | 描述 |
| --- | --- |
| openid | 微信用户的唯一标识 |
| session_key | 会话密钥 |
| unionid | 用户在微信开放平台的唯一标识符。本字段在满足一定条件的情况下才返回。|
`openid`就是前文一直提到的微信用户id,可以用这个id来区分不同的微信用户。
`session_key`则是微信服务器给开发者服务器颁发的身份凭证,开发者可以用session_key请求微信服务器其他接口来获取一些其他信息,由此可以看到,session_key不应该泄露或者下发到小程序前端。
设计session_key的原因:如果我们每次都通过小程序前端wx.login()生成微信登录凭证code去微信服务器请求信息,步骤太多造成整体耗时比较严重,因此对于一个比较可信的服务端,给开发者服务器颁发一个时效性更长的会话密钥就显得很有必要了。session_key也存在过期时间,具体内容可以参考小程序的官方文档关于session_key的相关介绍。
### 3.4.4 绑定微信用户身份id和业务用户身份
在3.4.2节提到,业务侧用户还没绑定微信侧身份时,会让用户填写业务侧的用户名密码,这两个值会和微信登录凭证一起请求开发者服务器的登录接口,此时开发者后台通过校验用户名密码就拿到了`业务侧的用户身份id`,通过code到微信服务器获取`微信侧的用户身份openid`。微信会建议开发者把这两个信息的对应关系存起来,我们把这个对应关系称之为“绑定”。
有了这个绑定信息,小程序在下次需要用户登录的时候就可以不需要输入账号密码,因为通过wx.login()获取到code之后,可以拿到用户的微信身份openid,通过绑定信息就可以查出业务侧的用户身份id,这样静默授权的登录方式显得非常便捷。
` ??.hy[这样静默授权的登录方式是否有风险] `
### 3.4.5 业务登录凭证SessionId
3.4.3节已经说到`微信侧返回的session_key`是开发者服务器和微信服务器的会话密钥,同样道理,开发者服务器和开发者的小程序应该也有会话密钥,在本书中我们就把它称之为`SessionId`。
>[info] hy:使用http协议,因为http协议是无状态协议,可以前端(browser)和后端(server)通过Session会话机制免去每次通信时的3次握手,从而提高通信效率。
> session_key中,前端:开发者服务器;后端:微信服务器
> SessionId中,前端:开发者的小程序;后端:开发者服务器
用户登录成功之后,开发者服务器需要生成会话密钥SessionId,在服务端保持SessionId对应的用户身份信息,同时把SessionId返回给小程序。小程序后续发起的请求中携带上SessionId,开发者服务器就可以通过服务器端的Session信息查询到当前登录用户的身份,这样我们就不需要每次都重新获取code,省去了很多通信消耗。我们在4.6.4还会提到如何利用本地数据缓存的能力把SessionId存储起来,以便在它还没过期的时候能重复利用,以提高通信的性能。
- 微信
- 小程序
- 1. 代码组成
- 1.1 JSON配置--'*.json'文件
- 1.2 WXML模板--'*.wxml'文件
- 1.3 WXSS样式--'*.wxss'文件
- 1.4 JavaScript脚本--'*.js'文件
- 2. 客户端运行
- 2.1 逻辑层和渲染层
- 2.1.1 逻辑层--App Service
- 2.1.2 渲染层/视图层--View
- 2.1.3 通信模型
- 2.1.4 数据驱动
- 2.1.5 双线程下的界面渲染
- 2.2 程序与页面
- 2.3 组件
- 2.4 API
- 2.5 事件
- 2.6 兼容
- 3. 应用设计
- 3.1 Flex布局
- 3.2 界面常见的交互反馈
- 3.3 发起HTTPS网络通信--wx.request
- 3.4 微信登录
- 3.5 本地数据缓存
- 3.6 设备能力
- 4. 小程序的协同工作和发布
- 4.1 协同工作
- 4.2 用户体验审视
- 4.3 发布
- 4.4 运营
- 5. 底层框架
- 5.1 双线程模型
- 5.2 组件系统--Exparser框架
- 5.3 原生组件
- 5.4 小程序与客户端通信原理
- 6. 运行和性能优化
- 6.1 启动--代码加载
- 6.2 页面准备
- 6.3 数据通信
- 6.4 视图层渲染
- 6.5 原生组件通信
- 7. 小程序基础库的更新迭代
- 8. 微信开发者工具
- 腾讯云支持
- wafer
- Wafer2 快速开发 Demo - PHP
- WXAPI
- api列表