小程序的登录和受权

1.小程序登陆

登入官方说明html

小程序能够经过微信官方提供的登陆能力方便地获取微信提供的用户身份标识,快速创建小程序内的用户体系。前端

登陆流程时序算法

说明:编程

  1. 调用 wx.login() 获取 临时登陆凭证code ,并回传到开发者服务器。
  2. 调用 code2Session 接口,换取 用户惟一标识 OpenID会话密钥 session_key

以后开发者服务器能够根据用户标识来生成自定义登陆态,用于后续业务逻辑中先后端交互时识别用户身份。json

注意:小程序

  1. 会话密钥 session_key 是对用户数据进行 加密签名 的密钥。为了应用自身的数据安全,开发者服务器不该该把会话密钥下发到小程序,也不该该对外提供这个密钥
  2. 临时登陆凭证 code 只能使用一次

兄弟们,是否是很简单,一看就会?我知道大家的回答以下图,可是不要慌,咱们详细讲每一步后端

小程序端执行wx.login后在回调函数中就能拿到上图的code,而后把这个code传给咱们后端程序,后端拿到这个这个code后,能够请求code2Session接口拿到用的openid和session_key,openid是用户在微信中惟一标识,咱们就能够把这个两个值(val)存起来,而后返回一个键(key)给小程序端,下次小程序请求咱们后端的时候,带上这个key,咱们就能找到这个val,就能够,这样就把登入作好了。api

1.1wx.login(Object object)

调用接口获取登陆凭证(code)。经过凭证进而换取用户登陆态信息,包括用户的惟一标识(openid)及本次登陆的会话密钥(session_key)等。用户数据的加解密通信须要依赖会话密钥完成。更多使用方法详见 小程序登陆安全

参数服务器

Object object

属性 类型 默认值 必填 说明 最低版本
timeout number 超时时间,单位ms 1.9.90
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

object.success 回调函数

参数

Object res

属性 类型 说明
code string 用户登陆凭证(有效期五分钟)。开发者须要在开发者服务器后台调用 code2Session,使用 code 换取 openid 和 session_key 等信息

示例代码

wx.login({
  success(res) {
    if (res.code) {
      // 发起网络请求
      wx.request({
        url: 'https://test.com/onLogin',
        data: {
          code: res.code
        },
        success: function (res) {
              wx.setStorageSync('login_key', res.data.data.login_key);
        }
      })
    } else {
      console.log('登陆失败!' + res.errMsg)
    }
  }
})

1.2code2Session

本接口应在服务器端调用,详细说明参见服务端API

登陆凭证校验。经过 wx.login() 接口得到临时登陆凭证 code 后传到开发者服务器调用此接口完成登陆流程。更多使用方法详见 小程序登陆

请求地址

GET https://api.weixin.qq.com/sns/jscode2sessionappid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

请求参数

属性 类型 默认值 必填 说明
appid string 小程序 appId
secret string 小程序 appSecret
js_code string 登陆时获取的 code
grant_type string 受权类型,此处只需填写 authorization_code

返回值

Object

返回的 JSON 数据包

属性 类型 说明
openid string 用户惟一标识
session_key string 会话密钥
unionid string 用户在开放平台的惟一标识符,在知足 UnionID 下发条件的状况下会返回,详见 UnionID 机制说明
errcode number 错误码
errmsg string 错误信息

errcode 的合法值

说明
-1 系统繁忙,此时请开发者稍候再试
0 请求成功
40029 code 无效
45011 频率限制,每一个用户每分钟100次

说完上面的登入后,咱们是否是尚未用到上面的session_key?这个就是在用户受权的时候用的,用来解密用户的数据,还要解密?是的你没有听错,不要慌,下面给你解释

2.微信受权获取用户信

后端获取微信用户信息流程

微信官方:忘了告诉你,session_key还会过时的,是的,没错就是这样坑爹。

个人回复:我就是头铁,我无论session_key过时,会带来什么样的后果呢?

微信官方:对不起,你头铁没有,你后端程序没法用户受权的数据,就问你气不气?

个人回复:好的,你牛逼,我能够接收你session_key过时,可是你要告诉我怎么判断他是过时的吧?怎么获取新的session_key吧?

微信官方:仍是要按照个人要求来吧?看你这么可怜,告诉你吧,用wx.checkSession判断是否过时,若是过时就重写登入吧!获取新的code,后端在去请求code2Session获取新的session_key

个人回复:好的,谢谢你sb

判断session_key有没有过时

2.1wx.checkSession(Object object)

检查登陆态是否过时。

经过 wx.login 接口得到的用户登陆态拥有必定的时效性。用户越久未使用小程序,用户登陆态越有可能失效。反之若是用户一直在使用小程序,则用户登陆态一直保持有效。具体时效逻辑由微信维护,对开发者透明。开发者只须要调用 wx.checkSession 接口检测当前用户登陆态是否有效。

登陆态过时后开发者能够再调用 wx.login 获取新的用户登陆态。调用成功说明当前 session_key 未过时,调用失败说明 session_key 已过时。更多使用方法详见 小程序登陆

参数

Object object

属性 类型 默认值 必填 说明
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

示例代码

wx.checkSession({
  success() {
    // session_key 未过时,而且在本生命周期一直有效
  },
  fail() {
    // session_key 已经失效,须要从新执行登陆流程
    wx.login() // 从新登陆
  }
})

微信官方:你要获取用的信息?我告诉你哈,若是要获取的话,要通过用户赞成的。

个人回复:sb,我怎么知道他是否受权过呢?若是没有受权,我怎么让他受权?

微信官方:你好,你能够调用wx.getSetting来判断,用户是否受权,若是没有受权,你要让他点击按钮,调起受权页面。用户点击赞成受权之后,你就能够调用wx.getUserInfo接口获取数据了*

个人回复:妈的,怎么这么麻烦?

微信官方:对不起,大佬,没有办法啊,咱们要保护用户的信息安全啊

个人回复:哦

2.2wx.getSetting(Object object)

基础库 1.2.0 开始支持,低版本需作兼容处理

获取用户的当前设置。返回值中只会出现小程序已经向用户请求过的权限

参数

Object object

属性 类型 默认值 必填 说明
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

object.success 回调函数

参数

Object res

属性 类型 说明
authSetting AuthSetting 用户受权结果

示例代码

wx.getSetting({
  success(res) {
    console.log(res.authSetting)
    //部分结果,若是为true,则表示该用户对这项权限以及受权,若是没有受权,咱们这须要经过button按钮让用户受权
    // res.authSetting = {
    //   "scope.userInfo": true,
    //   "scope.userLocation": true
    // }
  }
})

注意事项

  1. wx.authorize({scope: "scope.userInfo"}),不会弹出受权窗口,请使用 <button_open-type="getUserInfo">
  2. 须要受权 scope.userLocation 时必须配置地理位置用途说明

微信官方:当你小程序端调用咱们wx.getUserInfo的时候,咱们会返回你用的基本信息。

个人回复:什么是基本信息,哪些是敏感信息?我后端怎么获取呢?

微信官方:好比openid这些,大佬,你又两种方法,第一:你能够将这些基本信息传到后端,第二: 你能够讲getUserInfo中的 iv,encryptedData传给后端解密,机密后就能获取到用户的敏感信息了

个人回复:好的,我后端怎么解密呢?用什么解密呢?

微信官方:你登入的时候不是,后端不是存了session_key吗?加上这些数据,就能够解密了

个人回复:哦

2.3wx.getUserInfo(Object object)

获取用户信息

调用前须要 用户受权 scope.userInfo。

获取用户信息。

参数

Object object

属性 类型 默认值 必填 说明
withCredentials boolean 是否带上登陆态信息。当 withCredentials 为 true 时,要求此前有调用过 wx.login 且登陆态还没有过时,此时返回的数据会包含 encryptedData, iv 等敏感信息;当 withCredentials 为 false 时,不要求有登陆态,返回的数据不包含 encryptedData, iv 等敏感信息。
lang string en 显示用户信息的语言
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

object.lang 的合法值

说明
en 英文
zh_CN 简体中文
zh_TW 繁体中文

object.success 回调函数

参数

Object res

属性 类型 说明
userInfo UserInfo 用户信息对象,不包含 openid 等敏感信息
rawData string 不包括敏感信息的原始数据字符串,用于计算签名
signature string 使用 sha1( rawData + sessionkey ) 获得字符串,用于校验用户信息,详见 用户数据的签名验证和加解密
encryptedData string 包括敏感数据在内的完整用户信息的加密数据,详见 用户数据的签名验证和加解密
iv string 加密算法的初始向量,详见 用户数据的签名验证和加解密

接口调整说明

在用户未受权过的状况下调用此接口,将再也不出现受权弹窗,会直接进入 fail 回调(详见《公告》)。在用户已受权的状况下调用此接口,可成功获取用户信息。

示例代码

// 必须是在用户已经受权的状况下调用
wx.getUserInfo({
  success(res) {
    const userInfo = res.userInfo
    const nickName = userInfo.nickName
    const avatarUrl = userInfo.avatarUrl
    const gender = userInfo.gender // 性别 0:未知、1:男、2:女
    const province = userInfo.province
    const city = userInfo.city
    const country = userInfo.country
  }
})

encryptedData 解密后为如下 json 结构,详见加密数据解密算法

{
  "openId": "OPENID",
  "nickName": "NICKNAME",
  "gender": GENDER,
  "city": "CITY",
  "province": "PROVINCE",
  "country": "COUNTRY",
  "avatarUrl": "AVATARURL",
  "unionId": "UNIONID",
  "watermark": {
    "appid": "APPID",
    "timestamp": TIMESTAMP
  }
}

示例代码

<!-- 若是只是展现用户头像昵称,可使用 <open-data /> 组件 -->
<open-data type="userAvatarUrl"></open-data>
<open-data type="userNickName"></open-data>
<!-- 须要使用 button 来受权登陆 -->
<button
  wx:if="{{canIUse}}"
  open-type="getUserInfo"
  bindgetuserinfo="bindGetUserInfo"
>
  受权登陆
</button>
<view wx:else>请升级微信版本</view>

Page({
  data: {
    canIUse: wx.canIUse('button.open-type.getUserInfo')
  },
  onLoad() {
    // 查看是否受权
    wx.getSetting({
      success(res) {
        if (res.authSetting['scope.userInfo']) {
          // 已经受权,能够直接调用 getUserInfo 获取头像昵称
          wx.getUserInfo({
            success(res) {
              console.log(res.userInfo)
               wx.request({
                  url: url,
                  data: {
                    'iv': res.iv,
                    'encryptedData': res.encryptedData,
                    'login_key':登入标识
                  },
                  method: "POST",
                  header: {
                    'content-type': 'application/json' // 默认值
                  },
                  success: function (res) {
                    //解密后数据
                    console.log(res);
                  }
                });
            }
          })
        }
      }
    })
  },
  bindGetUserInfo(e) {
    console.log(e.detail.userInfo)
  }
})

叫你解密大法

2.4开放数据校验与解密

小程序能够经过各类前端接口获取微信提供的开放数据。考虑到开发者服务器也须要获取这些开放数据,微信会对这些数据作签名和加密处理。开发者后台拿到开放数据后能够对数据进行校验签名和解密,来保证数据不被篡改。

img

签名校验以及数据加解密涉及用户的会话密钥 session_key。 开发者应该事先经过 wx.login 登陆流程获取会话密钥 session_key 并保存在服务器。为了数据不被篡改,开发者不该该把 session_key 传到小程序客户端等服务器外的环境。

数据签名校验

为了确保开放接口返回用户数据的安全性,微信会对明文数据进行签名。开发者能够根据业务须要对数据包进行签名校验,确保数据的完整性。

  1. 经过调用接口(如 wx.getUserInfo)获取数据时,接口会同时返回 rawData、signature,其中 signature = sha1( rawData + session_key )
  2. 开发者将 signature、rawData 发送到开发者服务器进行校验。服务器利用用户对应的 session_key 使用相同的算法计算出签名 signature2 ,比对 signature 与 signature2 便可校验数据的完整性。

如 wx.getUserInfo的数据校验:

接口返回的rawData:

{
  "nickName": "Band",
  "gender": 1,
  "language": "zh_CN",
  "city": "Guangzhou",
  "province": "Guangdong",
  "country": "CN",
  "avatarUrl": "http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0"
}

用户的 session-key:

HyVFkGl5F5OQWJZZaNzBBg==

用于签名的字符串为:

{"nickName":"Band","gender":1,"language":"zh_CN","city":"Guangzhou","province":"Guangdong","country":"CN","avatarUrl":"http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0"}HyVFkGl5F5OQWJZZaNzBBg==

使用sha1获得的结果为

75e81ceda165f4ffa64f4068af58c64b8f54b88c

加密数据解密算法

接口若是涉及敏感数据(如wx.getUserInfo当中的 openId 和 unionId),接口的明文内容将不包含这些敏感数据。开发者如须要获取敏感数据,须要对接口返回的加密数据(encryptedData) 进行对称解密。 解密算法以下:

  1. 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
  2. 对称解密的目标密文为 Base64_Decode(encryptedData)。
  3. 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
  4. 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。

微信官方提供了多种编程语言的示例代码(点击下载)。每种语言类型的接口名字均一致。调用方式能够参照示例。

另外,为了应用能校验数据的有效性,会在敏感数据加上数据水印( watermark )

watermark参数说明:

参数 类型 说明
appid String 敏感数据归属 appId,开发者可校验此参数与自身 appId 是否一致
timestamp Int 敏感数据获取的时间戳, 开发者能够用于数据时效性校验

如接口 wx.getUserInfo 敏感数据当中的 watermark:

{
  "openId": "OPENID",
  "nickName": "NICKNAME",
  "gender": GENDER,
  "city": "CITY",
  "province": "PROVINCE",
  "country": "COUNTRY",
  "avatarUrl": "AVATARURL",
  "unionId": "UNIONID",
  "watermark": {
    "appid": "APPID",
    "timestamp": TIMESTAMP
  }
}

注:

  1. 解密后获得的json数据根据需求可能会增长新的字段,旧字段不会改变和删减,开发者须要预留足够的空间

会话密钥 session_key 有效性

开发者若是遇到由于 session_key 不正确而校验签名失败或解密失败,请关注下面几个与 session_key 有关的注意事项。

  1. wx.login 调用时,用户的 session_key 可能会被更新而导致旧 session_key 失效(刷新机制存在最短周期,若是同一个用户短期内屡次调用 wx.login,并不是每次调用都致使 session_key 刷新)。开发者应该在明确须要从新登陆时才调用 wx.login,及时经过 code2Session 接口更新服务器存储的 session_key。
  2. 微信不会把 session_key 的有效期告知开发者。咱们会根据用户使用小程序的行为对 session_key 进行续期。用户越频繁使用小程序,session_key 有效期越长。
  3. 开发者在 session_key 失效时,能够经过从新执行登陆流程获取有效的 session_key。使用接口 wx.checkSession能够校验 session_key 是否有效,从而避免小程序反复执行登陆流程。
  4. 当开发者在实现自定义登陆态时,能够考虑以 session_key 有效期做为自身登陆态有效期,也能够实现自定义的时效性策略。
相关文章
相关标签/搜索