微信小程序获取用户手机号

一、微信小程序获取用户手机号分四步:

1.微信前端登录接口wx.login获取临时登录凭证code

微信文档 https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html

 

2.后台根据code换取sessionKey

URL:https://api.weixin.qq.com/sns/jscode2session?appid={appId}&secret={appSecret}&grant_type=authorization_code&js_code={code}

该接口同时也会返回 openId和unionid

微信参考文档 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html

 

3.前端获取到encryptedData、iv

使用微信小程序的组件 button,open-type值为getPhoneNumber。

微信文档 https://developers.weixin.qq.com/miniprogram/dev/component/button.html

             https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html

4.encryptedData、iv、sessionKey三个参数调用后台解密接口解密即可得到微信小程序用户手机号

这一步有坑,详见下面

Java版解密工具类demo:

package com.meritdata.cloud.middleplatform.dataservice.cashier.utils;

import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.InvalidParameterSpecException;
import java.util.Arrays;


/**
 * 2020/12/14 5:08 PM
 *
 * @author shoo
 * @describe 解密工具类
 */
public class SecretUtilTools {
    public SecretUtilTools() {
    }

    public static String encryptForDES(String souce, String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
        SecureRandom sr = new SecureRandom();
        DESKeySpec dks = new DESKeySpec(key.getBytes("UTF-8"));
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey key1 = keyFactory.generateSecret(dks);
        Cipher cipher = Cipher.getInstance("DES");
        cipher.init(1, key1, sr);
        byte[] encryptedData = cipher.doFinal(souce.getBytes("UTF-8"));
        String base64Str = (new BASE64Encoder()).encode(encryptedData);
        return base64Str;
    }

    public static String decryptForDES(String souce, String key) throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, IOException, IllegalBlockSizeException, BadPaddingException {
        SecureRandom sr = new SecureRandom();
        DESKeySpec dks = new DESKeySpec(key.getBytes());
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey key1 = keyFactory.generateSecret(dks);
        Cipher cipher = Cipher.getInstance("DES");
        cipher.init(2, key1, sr);
        byte[] encryptedData = (new BASE64Decoder()).decodeBuffer(souce);
        byte[] decryptedData = cipher.doFinal(encryptedData);
        return new String(decryptedData, "UTF-8");
    }

    public static String decrypt(String data, String key, String iv, String encodingFormat) throws Exception {
        byte[] dataByte = Base64.decodeBase64(data);
        byte[] keyByte = Base64.decodeBase64(key);
        byte[] ivByte = Base64.decodeBase64(iv);
        int base = 16;
        if (keyByte.length % base != 0) {
            int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
            byte[] temp = new byte[groups * base];
            Arrays.fill(temp, (byte)0);
            System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
            keyByte = temp;
        }

        try {
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(2, spec, parameters);
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, encodingFormat);
                return result;
            }

            return null;
        } catch (NoSuchAlgorithmException var13) {
            var13.printStackTrace();
        } catch (NoSuchPaddingException var14) {
            var14.printStackTrace();
        } catch (InvalidParameterSpecException var15) {
            var15.printStackTrace();
        } catch (InvalidKeyException var16) {
            var16.printStackTrace();
        } catch (InvalidAlgorithmParameterException var17) {
            var17.printStackTrace();
        } catch (IllegalBlockSizeException var18) {
            var18.printStackTrace();
        } catch (BadPaddingException var19) {
            var19.printStackTrace();
        } catch (UnsupportedEncodingException var20) {
            var20.printStackTrace();
        }

        return null;
    }
}

   调用方法:

 

    public static MinAppUser getMiniUserInfo(String encryptedData, String iv, String sessionKey) throws IOException {
        MinAppUser minAppUser = new MinAppUser();
        String result = "";

        try {
            result = SecretUtilTools.decrypt(encryptedData, sessionKey, iv, "UTF-8");
            if (null != result && result.length() > 0) {
                minAppUser = (MinAppUser)(new ObjectMapper()).readValue(result, MinAppUser.class);

            } else {
                System.out.println("getMiniUserInfo error");
            }
        } catch (Exception var11) {
            var11.printStackTrace();
        }
        return minAppUser;
    }

 

二、以上四步步骤顺序不能错,否则各种报错。如:

1.解密报错 pad block corrupted

2.解密那一步,通过URL传参,不知道什么机制会自动把 "+" 换成 " ",导致你的encryptedData、iv错误。解决方法是反替换:

encryptedData = encryptedData.replaceAll(" ","+");
iv = iv.replaceAll(" ","+");

 

posted @ 2020-12-23 15:55  shog808  阅读(4078)  评论(1编辑  收藏  举报