阅读 123

小程序如何获取用户绑定的手机号

小程序官方文档中介绍:

获取微信用户绑定的手机号,需先调用wx.login接口。 因为需要用户主动触发才能发起获取手机号接口,所以该功能不由 API 来调用,需用 button 组件的点击来触发。

注意:目前该接口针对非个人开发者,且完成了认证的小程序开放(不包含海外主体)。需谨慎使用,若用户举报较多或被发现在不必要场景下使用,微信有权永久回收该小程序的该接口权限。具体可参考小程序API

使用方法 需要将 button 组件 open-type 的值设置为 getPhoneNumber,当用户点击并同意之后,可以通过 bindgetphonenumber 事件回调获取到微信服务器返回的加密数据, 然后在第三方服务端结合 session_key 以及 app_id 进行解密获取手机号。

    <button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号</button> 
复制代码

在使用组件之前先调用login

App({  
    onLaunch: function () {  
        wx.login({  
            success: function (res) {  
                if (res.code) {  
                    //发起网络请求 
                    this.globalData.code = res.code;
                    console.log(res.code)  
                } else {  
                    console.log('获取用户登录态失败!' + res.errMsg)  
                }  
            }  
        });  
    },
    globalData: {}
})
复制代码

getPhoneNumber中将返回用户是否同意授权的数据,

const App = getApp();
Page({
    getPhoneNumber(e) {
        const { iv, encryptedData, errMsg } = e.detail;
        if (errMsg === 'getPhoneNumber:ok') {
            // 同意授权
            wx.request({
                url: '/GetPhone',
                data: {
                    code: App.globalData.code,
                    iv,
                    encryptedData
                },
                success: (res) => {
                    console.log(res);
                }
            })
        }
    }
})
复制代码

后端需要根据前端传递的code,iv, encryptedData,结合小程序的appID,secret,先获取session_key,然后在进行电话号码解析。为了安全考虑,我们的appID和secret都是存放在后端的,所以获取session_key和电话解析都放后端进行了,前端只需调用接口即可。

获取session_key的地址


const APP_ID = '';
const SECRET = '';
const BASE_URL = 'https://api.weixin.qq.com';

const url = `${BASE_URL}/sns/jscode2session?appid=${APP_ID}&secret=${SECRET}&js_code=${res.code}&grant_type=authorization_code`;
复制代码

电话号码解析实例(java版)

import org.apache.shiro.codec.Base64;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;

@Controller

public class GetPhone {
    /*用户手机号解析*/
    @RequestMapping("/getPhoneNumber")
    @ResponseBody
    public String getPhoneNumber(String encryptedData, String iv, String sessionKey) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, UnsupportedEncodingException {

        System.out.println(encryptedData + "-------" + iv + "-------" + sessionKey);

        byte[] encData = Base64.decode(encryptedData);
        byte[] keyByte = Base64.decode(iv);
        byte[] key = Base64.decode(sessionKey);

        AlgorithmParameterSpec ivSpec = new IvParameterSpec(keyByte);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);// 初始化
        byte[] resultByte = cipher.doFinal(encData);
        if (null != resultByte && resultByte.length > 0) {
            String result = new String(resultByte, "UTF-8");
            System.out.println(result);
            return result;
        }
        return null;
    }
复制代码

注意:在回调中调用 wx.login 登录,可能会刷新登录态。此时服务器使用 code 换取的 sessionKey 不是加密时使用的 sessionKey,导致解密失败。建议开发者提前进行 login;或者在回调中先使用 checkSession 进行登录态检查,避免 login 刷新登录态。

最后提醒大家,进入一个未知的小程序时,弹出用户授权询问框时,谨慎授权。如下图