受欢迎的博客标签

微信小程序云开发(1)-小程序云开发用户openid的获取与授权

Published

UnionID 机制说明

如果开发者拥有多个移动应用、网站应用、和公众帐号(包括小程序),可通过 UnionID 来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用、网站应用和公众帐号(包括小程序),用户的 UnionID 是唯一的。换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。

UnionID获取途径

 

小程序端调用云函数

绑定了开发者帐号的小程序,可以通过下面 4 种途径获取 UnionID。


小程序端调用云函数时,如果开发者帐号下存在同主体的公众号,并且该用户已经关注了该公众号,可在云函数中通过 cloud.getWXContext 获取 UnionID
小程序端调用云函数时,如果开发者帐号下存在同主体的公众号或移动应用,并且该用户已经授权登录过该公众号或移动应用,也可在云函数中通过 cloud.getWXContext 获取 UnionID。

原文:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/union-id.html

 

1.正常的方式,这些信息不需要用户授权即可获取,获取unionid

step 1:

使用云函数只能获取的用户的openid 和 appid两项信息,结构如下:

云函数[login] user event:
 {
   userInfo: 
   { 
     appId: 'wxf7058cc***',
     openId: 'oQuJV43etcpx6W5gZBLv**' 
   } 
 }

 

step 2.用户图像和昵称授权代码

如果要获取用户的图像等信息,必须要用户显式授权后才可获取到

下面的代码用来显示图像或提示信息,让用户点击(图像或提示文字),以便弹出授权窗口,让用户进行选择授权或拒绝授权。

 <view class='info'>
      <label>
      
        <image class='avatar' src='{{avatarUrl|| defaultAvatarUrl}}'></image>
        <view class='text'>
          <view class='name'>{{userInfo.nickName || '登录/注册'}}</view>
          <view>{{userInfo.jobTitle || '添加职位'}} @ {{userInfo.company || '添加公司'}}</view>
        </view>
        <button open-type='getUserInfo' bindgetuserinfo='onGetUserInfo'></button>
      </label>
    </view>

用户选择授权或拒绝后,立即调用下面的代码。下面这段代码用来判断用户是否授权了。

//用户点击图标后,会弹出“微信授权” 窗口
// 用户点击“允许”,允许开发者获得用户的公开信息(昵称、头像等)
  onGetUserInfo: function (e) {
    if (!this.logged && e.detail.userInfo) {
      this.setData({
        logged: true,
        avatarUrl: e.detail.userInfo.avatarUrl,
        userInfo: e.detail.userInfo
      })
    }
  },

step 3: 后台判断用户是否授权的代码

这段代码用来在任何时候判断用户是否已授权,上面那个是有弹窗后的立马判断。

/**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {


    // 使用 wx.getSetting 获取用户当前的用户信息授权状态。获取用户图像和昵称信息。
    wx.getSetting({
      success: res => {
        if (res.authSetting['scope.userInfo']) {
          // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
          console.log('已经授权')
          wx.getUserInfo({
            success: res => {
              
              this.setData({
                avatarUrl: res.userInfo.avatarUrl,
                userInfo: res.userInfo
              })

              // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
              // 所以此处加入 callback 以防止这种情况
              if (this.userInfoReadyCallback) {
                this.userInfoReadyCallback(res)
              }


            }
          })
        }
        else {
          console.log('page/my/my|res.authSetting:', '小程序AspNetCore自定义:检测到当前用户未授权获取图像和昵称') 
          
          wx.showToast({
            title: "提示:您未授权本程序获取您的图像和昵称。如果您愿意,请点击图像授权(这不是必须的,不授权程序可以正常工作)",
            duration: 5000,
            icon: "none"
          })
        }

      }
    })

  },

2.open-data头像、昵称获取方式

如果只是为了展示用户名和头像可以用open-data组件,wx.getUserInfo还是可以使用,只是第一次授权必须要经过button组件而已。

<view class="userinfo">
  <view class="userinfo-avatar">
    <open-data  type="userAvatarUrl"></open-data>
  </view>
    <open-data type="userNickName"></open-data>
</view
.userinfo {
  position: relative;
  width: 750rpx;
  height: 320rpx;
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
}
 
.userinfo-avatar {
  overflow:hidden;
  display: block;
  width: 160rpx;
  height: 160rpx;
  margin: 20rpx;
  margin-top: 50rpx;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.2);
}
 
.userinfo text {
  /* color: #fff; */
  font-size: 14px;
  background-color: #c0c0c0;
  border-radius:40%;
}

微信小程序wx.login()、wx.getSetting、wx.getUserInfo的区别

1、wx.login
前端使用wx.login是获取登录凭证(code),将code发送给后台,后台向微信发送请求获取用户的唯一标识(openid)及本次登录的会话密钥(session_key),然后后台传回前台自定义的登录状态,以及自定义的用户唯一标识

2、wx.geUserInfo
wx.getuserinfo是为了获取用户的相关信息

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

 

接口还是有的,通过login拿到code,去后台通过restful api可以拿到openid和unoinid.用户使用button(小程序)或UserInfoButton(小游戏)组件,在用户点击后弹窗请求获取用户基本信息。我的建议是能不用getUserInfo的地方尽量不用,可以用open-data替代,从而不需要授权。例如获取头像,昵称等信息,如果后台不需要存储这些数据,就使用open-data(如果应用不需要展示其他好友的头像、昵称,后台就可以不存储这些数  据)。

 同时,为了区分用户,只需通过wx.login()来获取openId,作为用户ID给后台存储就行了(需要用到Unionid的除外),这种情况也不需要授权。

 

    let customer =  Customer;

    //---直接对data赋值,不会引起界面刷新---


    customer.Appid = app.globalData.appid,
      customer.Unionid = app.globalData.unionid,
      customer.Openid = app.globalData.openid,
      customer.AuthorOpenid = app.globalData.openid,
      customer.UserInfo = {},

      customer.UserName = "",
      customer.TelephoneNumber = "",

      customer.EmployeeRoles = {}, //员工角色
      customer.Level = 0,  //权限级别
      customer.ShopRoles = {}, //员工角色
      customer.IsEmployee = true, // 是否员工

      customer.IsAuthorized = false, // 是否已取得授权

      customer.CreatedOnUtc = db.serverDate(),
      customer.UpdatedOnUtc = db.serverDate(),
      customer.LastloginOntUtc = db.serverDate(),

      console.log("Customer记录", customer)
    //如果没有有数据,则插入用户数据, data 字段表示需新增的 JSON 数据
    if (!users.data.length) {
     

      db.collection(collection).add({
        data: customer,
        success: res => {
          console.log('pages/adminEmployee/index/index 插入用户数据 ok')
        },
        fail: err => {
          console.error('ppages/adminEmployee/index/index 插入数据 failure', err)

        }
      })



    }

 

 

miniprogram/pages/adminEmployee/login/index.js

// miniprogram/pages/adminEmployee/login/index.js

let app = getApp();
// 获取云数据库引用
const db = wx.cloud.database();


const configCollection = require('../../../config/configCollection.js');
const Customer = require('../../../models/Customer/Customer.js');
//const collection = 'Setting';
const collection = configCollection.Setting;

let name = null;
let password = null;

Page({

  /**
   * 页面的初始数据
   */
  data: {
    userInputPassword: "",
    AdminPassword: "",//从数据库中获取管理后台密码
    isEmployee: false, // 是否公司员工

    ObjectId: "",

    Employee: {

      _id: "",

      Appid: app.globalData.appid,
      AuthorOpenid: app.globalData.openid,
      AuthorUnionid: app.globalData.unionid,
      riginalId: app.globalData.OriginalId,

      UserInfo: {},

      IsAuthorized: false, // 是否已取得授权
      IsEmployeeAuthorized: false, // 是否员工认证

      CreatedOnUtc: db.serverDate(),
      UpdatedOnUtc: db.serverDate(),
      LastloginOnUtc: db.serverDate(),

    },

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

    //从数据库中获取管理后台密码
    const db = wx.cloud.database();
    db.collection(configCollection.Setting).where({
      Name: "AdminPassword"
    }).get({
      success: res => {
        this.setData({
          AdminPassword: res.data[0], //返回的是一个数组,取第一个,

        })
      },
      fail: err => {
        console.log(err)
      }
    })


    //自定义ObjectId
    // 调用云函数获取ObjectId,string类型
    wx.cloud.callFunction({
      name: 'http',
      data: {},
      success: res => {
        this.data.ObjectIdGenerateNewId = res.result;
        console.log('[云函数] [http]: ', res)

      },
      fail: err => {
        console.error('[云函数] [http] 调用失败', err)

      }
    })




  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {


  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  },

  //输入用户名
  userNameChange: function (e) {
    this.data.username = e.detail.value;
  },
  //输入密码
  userPasswordChange: function (e) {
    this.data.userInputPassword = e.detail.value;
  },

  toadmin: function () {
    var that = this;
    if (that.data.userInputPassword == '') {
      wx.showModal({
        title: '请填写密码',
        showCancel: false
      })
      return
    }

    if (that.data.userInputPassword != that.data.AdminPassword.Password) {
      wx.showModal({
        title: '您填写的密码不对',
        showCancel: true
      })
      return
    }

    if (that.data.userInputPassword === that.data.AdminPassword.Password) {

      //密码验证通过
      app.globalData.EmployeeAdminPasswordIsAuthorized = true;

      // 调用云函数创建员工用户
      wx.cloud.callFunction({
        name: 'loginEmployee',
        data: {
          ObjectIdGenerateNewId:that.data.ObjectIdGenerateNewId,  //传给云函数的参数
        },
        success: res => {
          console.log('调用云函数loginEmployee:', res)
        },
        fail: err => {
          console.error('[云函数] [loginEmployee] 调用失败', err)
        }
      })



      //获取员工对象数据结构,并且将Id替换wei_id
      // that.getNewEmployeeFromApi();
      //that.getNewObjectId();

     



      const db = wx.cloud.database(); //打开数据库连接
      //对象赋值
      let employee = that.data.Employee;

      console.log(configCollection.Employee + "编辑后的记录内容", configCollection.Employee)

      employee._id = that.data.ObjectId;



      employee.Appid = app.globalData.appid;
      employee.OriginalId = app.globalData.minappOrigalid;
      employee.AuthorUnionid = app.globalData.unionid;
      employee.AuthorOpenid = app.globalData.openid;


      employee.EmployeeStatus = 20;

      employee.CreatedOnUtc = db.serverDate();
      employee.UpdatedOnUtc = db.serverDate();
      employee.LastloginOnUtc = db.serverDate();
      employee.LastloginIP = "";

      console.log(configCollection.Employee + ":", configCollection.Employee)

      //避免在直接对 Page.data 进行赋值修改,使用 Page.setData 进行操作才能将数据同步到页面中进行渲染

      that.setData({ employee })




      //获取该员工的信息

      db.collection(configCollection.Employee).where({
        AuthorOpenid: app.globalData.openid
      }).get({
        success: res => {
          let employees = res.data;
          console.log("后台index获取的员工信息" + res.data)

          //有此员工数据
          if (Employees && Employees.length > 0) {

          }
          else  //无此员工数据,导航到登录页面
          {

            wx.navigateTo({
              url: '/pages/adminEmployee/login/index'
            });

          }


        },
        fail: err => {
          console.log(err)
        }
      })

      db.collection(configCollection.Employee).add({
        data: that.data.employee,
        success: res => {
          console.log('pages/adminEmployee/login/index 插入数据 success')

        },
        fail: err => {
          console.error('pages/adminEmployee/login/index 插入数据 failure', err)

        }
      })



      //  wx.navigateTo({
      //   url: '/pages/adminEmployee/index/index'
      //   });
    }
    else {
      wx.navigateTo({
        url: '/pages/my/index'
      });
    }


  },

  //getNewObjectId
  getNewObjectId: function () {
    var that = this;

    wx.request({
      url: 'https://api.usdotnet.com/api/ObjectId', //仅为示例,并非真实的接口地址
      data: {

      },
      header: {
        'content-type': 'application/json' // 默认值
      },
      success(res) {
        console.log(res.data)

        that.setData({
          ObjectId: res.data
        })
      },
      fail: function (res) {
        console.log("失败" + res);
      }

    })


  },

  //获取1个员工对象
  getNewEmployeeFromApi: function () {
    var that = this;

    wx.request({
      url: 'https://api.usdotnet.com/api/Employee/NewEmployee', //仅为示例,并非真实的接口地址
      data: {

      },
      header: {
        'content-type': 'application/json' // 默认值
      },
      success(res) {
        console.log(res.data)

        //json对象转成json字符串
        var jsonobj = res.data;
        var jsonstr = JSON.stringify(jsonobj);
        console.log("jsonstr==" + jsonstr)

        var idstring = '"Id":';
        var _idstring = '"_id":';

        jsonstr = jsonstr.replace(idstring, _idstring);


        jsonstr = jsonstr.replace(new RegExp(idstring, 'g'), _idstring);

        console.log("jsonstr00==" + jsonstr)

        let jsonobj2 = JSON.parse(jsonstr);
        that.setData({
          Employee: jsonobj2
        })


      },
      fail: function (res) {
        console.log("失败" + res);
      }

    })


  },

})

 

常见问题

1.本地云函数被删除后,提示找不到云函数

解决办法:同步云函数列表

2.页面加载后仍未获取到openId

原因:app.js里的onLaunch(异步)方法调用得到数据的速度比页面Page中的onLoad慢,导致在加载index.wxml时openid总是为空

解决办法:采用Promise

 

普通小程序端调用

 

 

 

目录:

画图Canvas:https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.setTextAlign.html

 

小程序分享及用户信息授权等接口能力10月10调整

https://mp.weixin.qq.com/cgi-bin/announce?action=getannouncement&announce_id=11536230584k14IW&version=&lang=zh_CN&token=1525354655