一、微信小程序获取用户手机号分四步:
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(" ","+");