您的当前位置:首页正文

微信小程序之登录

2024-11-29 来源:个人技术集锦


        小程序可以通过微信官方提供的登录能力方便地获取微信提供的用户身份标识,快速建立小程序内的用户体系。详情查看:

1、登录流程时序

说明

之后开发者服务器可以根据用户标识来生成自定义登录态,用于后续业务逻辑中前后端交互时识别用户身份

注意事项

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

1.1、wx.login(Object object)

1.1.1、功能描述

        调用接口获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台帐号下的唯一标识(unionid,若当前小程序已绑定到微信开放平台帐号)及本次登录的会话密钥(session_key)等。用户数据的加解密通讯需要依赖会话密钥完成

1.1.2、参数

属性类型默认值必填说明
timeoutnumber超时时间,单位ms
successfunction接口调用成功的回调函数
failfunction接口调用失败的回调函数
completefunction接口调用结束的回调函数(调用成功、失败都会执行)

1.1.3、object.success 回调函数

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

1.2、auth.code2Session

        注意:这个作用于服务端,不要在客户端调用

        登录凭证校验。通过  接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程

1.2.1、请求地址

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

1.2.2、请求参数

属性类型默认值必填说明
appidstring小程序 appId
secretstring小程序 appSecret
js_codestring登录时获取的 code
grant_typestring授权类型,此处只需填写 authorization_code

1.2.3、返回值

属性类型说明
openidstring用户唯一标识
session_keystring会话密钥
unionidstring用户在开放平台的唯一标识符,若当前小程序已绑定到微信开放平台帐号下会返回,详见 。
errcodenumber错误码
errmsgstring错误信息

errcode 的合法值

说明
-1系统繁忙,此时请开发者稍候再试
0请求成功
40029code 无效
45011频率限制,每个用户每分钟100次
40226高风险等级用户,小程序登录拦截 。风险等级详见

        我真的是晕倒了,如果你使用的是云开发自带的数据库来存储的话,其实你是不需要获取openid的行为的,但是我一开始不知道呀,弄着弄着发现其实这个是有的,所以就分了两个了,一个是获取微信头像、昵称和openid的,一个是使用自带的获取手机号码的

2、使用微信登录

工作步骤:

  1. wx.getUserProfile弹窗框体显示用户的头像和昵称
  2. 确定后wx.login获取code
  3. 发送命令到服务器获取openid以及账户信息

 2.1、小程序端js文件

async getUserProfile(e) {
    wx.getUserProfile({
      desc: '用于获取用户个人信息',
      success: function (detail) {
        
        wx.login({
          success: res => {
            var code = res.code; //登录凭证
            wx.cloud.callFunction({
              name: "getCurrentUserInfo",
              data: {
                encryptedData: detail.encryptedData,
                iv: detail.iv,
                code: code,
                userInfo: detail.rawData
              }
            }).then(res => {
              console.log("res: ",res);
              var openid = res.result.openid;
              var status = res.result.status;
              var phone = res.result.phone;
              console.log("openid: ",openid);
              console.log("status: ",status);
              console.log("phone: ",phone);
              console.log("nickName: ",detail.userInfo.nickName);
              
              if(phone==undefined){
                console.log("需要绑定手机号");
              }else{
                console.log("授权成功");
              }
            }).catch(res => {
              console.log("res3: ",res);
            })
          }
        });
      },
      fail: function () {
       wx.showModal({
         content: '取消授权将会影响相关服务,您确定取消授权吗?',
         success (res) {
           if (res.confirm) {
             wx.showToast({
               title: '已取消授权',
               duration: 1500
             })
           } else if (res.cancel) {
             this.getUserProfile()
           }
         }
       })
      }
    })
  }

2.2、云函数端js文件

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})
const db = cloud.database()
// 云函数入口函数
let user_id;
let user_uid;
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  let code = event.code;//获取小程序传来的code
  let encryptedData = event.encryptedData;//获取小程序传来的encryptedData
  let iv = event.iv;//获取小程序传来的iv
  let userInfo = JSON.parse(event.userInfo) //获取个人信息
  let appid = "xxxxxxxxx";//自己小程序后台管理的appid,可登录小程序后台查看
  let secret = "xxxxxxxxx";//小程序后台管理的secret,可登录小程序后台查看
  let grant_type = "authorization_code";// 授权(必填)默认值
  let url = "https://api.weixin.qq.com/sns/jscode2session?grant_type="+grant_type+"&appid="+appid+"&secret="+secret+"&js_code="+code;
  const stat = await new Promise((resolve, reject) => {
    request(url, (err, response, body) => {
      if (!err && response.statusCode == 200) {
        let _data = JSON.parse(body)
        let UserCount = 0;
        user_id = _data.openid
        user_uid = _data.unionid
        db.collection('Account').where({
          user_id: _data.openid // 填入当前用户 openid
        }).count().then(res => {
          UserCount = res.total;
          if(UserCount == 0){/* 插入当前列表 */
            db.collection('Account').add({
              data: {
                user_id: _data.openid,
                nickName: userInfo.nickName,
                avatarUrl: userInfo.avatarUrl,
                gender: userInfo.gender,
                phone: ''
              }
            })
            .then(res => {
              resolve("Insert success!");
            })
            .catch(res => {
              reject("Insert fail!");
            })
          }else if(UserCount == 1){/* 更新当前列表 */
            db.collection('Account').where({
              user_id: _data.openid // 填入当前用户 openid
            }).update({
              data: {
                nickName: userInfo.nickName,
                avatarUrl: userInfo.avatarUrl,
                gender: userInfo.gender
              }
            })
            .then(res => {
              resolve("Update success!");
            }).catch(res => {
              reject("Update fail!");
            })
          }else if(UserCount > 1){/* 删除所有此id的并且重新添加 */
            db.collection('Account').where({
              user_id: _data.openid // 填入当前用户 openid
            }).remove()
            .then(res => {
              db.collection('Account').add({
                data: {
                  user_id: _data.openid,
                  nickName: userInfo.nickName,
                  avatarUrl: userInfo.avatarUrl,
                  gender: userInfo.gender,
                  phone: ''
                }
              })
              resolve("Remove and insert success!");
            }).catch(res => {
              reject("Remove fail!");
            })
          }
        })
      }
    })
  })
  const CurrentPhoneObject = await db.collection('Account').where({
    user_id: user_id // 填入当前用户 openid
  }).get()
  const CurrentPhone = CurrentPhoneObject.data[0].phone
  console.log("CurrentPhone: ",CurrentPhone);
  console.log("stat: ",stat);
  console.log("user_id: ",user_id);
  console.log("user_uid: ",user_uid);
  return {
    status: stat,
    CurrentPhone: CurrentPhone,
    openid: user_id,
    unionid: user_uid
  }
}

3、获取手机号码

        因为需要用户主动触发才能发起获取手机号接口,所以该功能不由 API 来调用,需用  组件的点击来触发。另外,新版本接口不再需要提前调用wx.login进行登录。

<button type="primary" open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号</button>

3.1、小程序端代码

 async getPhoneNumber(res) {
    console.log(res)
    const errMsg = res.detail.errMsg
    if (errMsg != "getPhoneNumber:ok"){
      wx.showToast({
        title: '授权失败',
        icon: 'error'
      })
      return
    }
    const cloudId = res.detail.cloudID
    const cloudIdList = [cloudId]
    wx.showLoading({
      title: '获取中',
      mask: true
    })
    const cloudFunRes = await wx.cloud.callFunction({
      name: "getPhoneNumber",
      data: {
        cloudIdList
      }
    })
    console.log("cloudFunRes: ",cloudFunRes)
    const jsonStr = cloudFunRes.result.dataList[0].json
    const jsonData = JSON.parse(jsonStr)
    const phoneNumber = jsonData.data.phoneNumber
    console.log(phoneNumber)
    this.setData({
      userPhone: phoneNumber
    })
    wx.hideLoading({
      success: (res) => {},
    })
  },

3.2、云函数端js文件

const cloud = require('wx-server-sdk')

cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
})

// 云函数入口函数
exports.main = async (event) => {
  const wxContext = cloud.getWXContext()
  const openid = wxContext.OPENID
  const appid = wxContext.APPID
  const unionid = wxContext.UNIONID
  const enc = wxContext.ENV
  const cloudIdList = event.cloudIdList
  try {
    const result = await cloud.openapi.cloudbase.getOpenData({
      openid: openid,
      cloudidList: cloudIdList
    })
    
    const jsonStr = result.dataList[0].json
    const jsonData = JSON.parse(jsonStr)
    const phoneNumber = jsonData.data.phoneNumber
    console.log("phoneNumber: ",phoneNumber)

    return result
  } catch (err) {
    return err
  }
}

主要代码来自博主:

显示全文