Skip to content
On this page

实战篇 8-微信小程序端用户授权处理


微信小程序端用户授权处理

获取用户信息需要授权已经是互联网的共识了,各手机系统和公司的应用都十分重视这一块。但在大数据时代,拥有数据便是拥有某些能力在诱惑着很多公司游走在法律边缘,作为非常重视用户信息的微信,小程序的开发者要拿到用户信息需要用户先授权才行。

微信授权

小程序里使用 wx.authorize(OBJECT) 提前向用户发起授权请求。调用后会立刻弹窗询问用户是否同意授权小程序使用某项功能或获取用户的某些数据,但不会实际调用对应接口。如果用户之前已经同意授权,则不会出现弹窗,直接返回成功。需要授权的信息有:用户信息、地理位置、通讯地址、发票抬头、微信运动步数、录音功能、保存到相册、摄像头,其中最常用等莫过于用户信息了。使用 wx.getUserInfo() 可以获取用户信息。

wx.authorize(OBJECT)wx.getUserInfo() 的关系是什么呢?wx.authorize(OBJECT) 是提前向用户发起授权请求,调用后会立刻弹窗询问用户,不会实际调用接口,用户已经同意小程序使用用户信息,后续调用 wx.getUserInfo() 接口不会弹窗询问。

在 2018 年 4 月 30 号之前的小程序里,调用 wx.getUserInfo() 接口会出现授权窗口。在该日期之后,微信优化了用户体验,小程序的体验版、开发版调用wx.getUserInfo 接口,将无法弹出授权询问框,默认调用失败,但正式版暂不受影响。

不出现用户授权弹窗,同时又需要 <button open-type="getUserInfo"></button> 引导用户主动进行授权操作,微信为什么这么改呢?因为大部分小程序并不考虑进入小程序是否申请授权,而不是在需要的时候才申请授权。站在用户的角度来说,还是有些心理压力,毕竟都还没有看到页面,点进来可能仅仅因为是朋友分享到群里或者朋友圈,进入就要被索要个人信息,无形之中产生压力。另外,如果后续只能通过 <open-data></open-data> 来显示用户个人信息,那么开发者既可以显示相应的信息而又不被开发偷偷保存并泄漏出去。

// 需要点击「获取用户信息」才会执行 onGotUserInfo
<button open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="onGotUserInfo">获取用户信息</button>
// 展示用户头像、用户昵称
<open-data type="userAvatarUrl"></open-data>
<open-data type="userNickName" lang="zh_CN"></open-data>

试想,如果页面上一个需要展示用户信息的区域,出现一个按钮“微信授权登陆”,你点击后显示你头像和昵称,十分优雅。

有时候现实总是迫不得已,如果我们需要用户一进入就取得用户的授权,以便于进行某些记录用户信息的操作,而微信又要求用户去点页面上的某个按钮才能获取信息,那怎么办呢?只能把一个按钮放在用户不能不点的地方,那就只有弹窗了。微信 wx.showModal 不能满足我们的需求,只能自己造一个,在用户第一次进来的时候弹窗,再次进来的时候则不显示。为了让这个组件具有拓展性,我们根据传入的值来修改 确认 位置按钮的属性,如果是授权的弹窗就改按钮属性为 openType='getUserInfo'

import Taro, { Component } from '@tarojs/taro'
import { View, Text } from '@tarojs/components'

import './modal.scss'

class Modal extends Component {
  constructor() {
    super(...arguments)
    this.state = {}
  }

  confirmClick = () => {
    this.props.onConfirmCallback()
  }

  cancelClick = () => {
    this.props.onCancelCallback()
  }

  authConfirmClick = (e) => {
    this.props.onConfirmCallback(e.detail)
  }

  preventTouchMove = (e) => {
    e.stopPropagation()
  }

  render() {
    const { title, contentText, cancelText, confirmText} = this.props
    return (
      <View class='toplife_modal' onTouchMove={this.preventTouchMove}>
        <View class='toplife_modal_content'>
          <View class='toplife_modal_title'>{title}</View>
          <View class='toplife_modal_text'>{contentText}</View>
          <View class='toplife_modal_btn'>
            <Button class='toplife_modal_btn_cancel' onClick={this.cancelClick}>{cancelText}</Button>
            {!isAuth ?
              <Button class='toplife_modal_btn_confirm' onClick={this.confirmClick}>{confirmText}</Button> :
            <Button class='toplife_modal_btn_confirm' openType='getUserInfo' onGetuserinfo={this.authConfirmClick} onClick={this.cancelClick}>授权</Button> }
          </View>
        </View>
      </View>
    )
  }
}

Modal.defaultProps = {
  title: '',
  contentText: '',
  cancelText: '取消',
  confirmText: '确定',
  isAuth: false,
  cancelCallback: () => {},
  confirmCallback: () => {},
}

export default Modal

Modal 组件还算比较简单,组件的属性:

字段说明
title提示的标题
contentText提示的描述
cancelText取消按钮的文案
cancelCallback取消回调的函数
confirmText确认按钮的文案
confirmCallback确认回调函数
isAuth标记是否为授权按钮

细心的读者可能发现了,我们在内部设置了一个函数 preventTouchMove,其作用是弹窗出现蒙层的时候,阻止在蒙版上的滑动手势 onTouchMove。另外一个函数 authConfirmClick, 当 isAuth 为真时,确认按钮为取得个人信息的授权按钮,此时把个人信息当值传递给调用的函数。

在引用该组件的时候,如下面这个页面:

import Taro, { Component, eventCenter } from '@tarojs/taro'
import Modal from '../../components/gb/modal/modal'
class Index extends Component {
  constructor() {
    super(...arguments)
    this.state = {
      showAuthModal: false
    }
    this.$app = this.$app || {}
  }
  hideAuthModal () {
    this.setState({
      showAuthModal: false
    })
    Taro.setStorageSync('isHomeLongHideAuthModal', true)
  }

  prcoessAuthResult (userData) {
    Taro.setStorageSync('isHomeLongHideAuthModal', true)
    if (userData.userInfo) {
      this.$app.userData = userData
    }
    this.setState({
      showAuthModal: false
    })
  }
  render () {
    const { showAuthModal } = this.state
    return (
      <View className={indexClassNames}>
        {showAuthModal && <Modal
          title={'授权提示'}
          contentText={'Taro电商邀您完成授权,尊享时尚奢华之旅'}
          onCancelCallback={this.hideAuthModal.bind(this)}
          onConfirmCallback={this.prcoessAuthResult.bind(this)}
          isAuth={true} />}
      </View>
    )
  }
}

我们是如何保证这个应用只有一次授权弹窗呢? 关键代码是 Taro.setStorageSync('isHomeLongHideAuthModal', true) ,如果弹出了一次,就在本地存一个标记已经弹过授权框,下一次弹窗之前可以根据此判断。

至此我们完成了授权处理,但如果可以的话还是要优雅一些,在需要的时候才征求用户授权,保证用户体验。

参考资料:

《小程序与小游戏获取用户信息接口调整,请开发者注意升级。》 —— 微信团队