微信小程序一键登录获取手机号
一、前端
1、请求发送 携带 code 到后台换取 openid。
var that = this; wx.login({ success(res) { console.log(res); var code = res.code wx.request({ url: 'http://localhost/index/users/code2seesion', method: "post", data: { code }, success: function (res) { console.log(res.data.openid); that.setData(res.data); } }) } })
在app.js的onLaunch方法中运行,然后保存在globalData,保存data内容 里面包含 openid 和 session_key 。
二、获取手机号
<button open-type="getPhoneNumber" bindgetphonenumber="getPhoneNumber">获取手机号</button>
getPhoneNumber: function (e) { var that = this; console.log(e.detail.errMsg == "getPhoneNumber:ok"); if (e.detail.errMsg == "getPhoneNumber:ok") { wx.request({ url: 'http://localhost/index/users/decodePhone', data: { encryptedData: e.detail.encryptedData, iv: e.detail.iv, sessionKey: that.data.session_key, uid: "", }, method: "post", success: function (res) { console.log(res); } }) } },
点击后将加密的信息传至java后台进行解密,再进行使用。
二、Java后端解密数据
1、实体类
(1)微信手机号信息解密后的对象
import com.alibaba.fastjson.JSON; /** * @description: 微信手机号信息解密后的对象 * @author: wrt */ public class WeixinPhoneDecryptInfo { private String phoneNumber; private String purePhoneNumber; private int countryCode; private String watermark; private WeixinWaterMark weixinWaterMark; public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } public String getPurePhoneNumber() { return purePhoneNumber; } public void setPurePhoneNumber(String purePhoneNumber) { this.purePhoneNumber = purePhoneNumber; } public int getCountryCode() { return countryCode; } public void setCountryCode(int countryCode) { this.countryCode = countryCode; } public String getWatermark() { return watermark; } public void setWatermark(String watermark) { this.watermark = watermark; this.weixinWaterMark = JSON.toJavaObject(JSON.parseObject(this.watermark),WeixinWaterMark.class); } public WeixinWaterMark getWeixinWaterMark(){ return weixinWaterMark; } @Override public String toString() { return "WeixinPhoneDecryptInfo{" + "phoneNumber='" + phoneNumber + '\'' + ", purePhoneNumber='" + purePhoneNumber + '\'' + ", countryCode=" + countryCode + ", appid=" + weixinWaterMark.getAppid() + ", timestamp=" + weixinWaterMark.getTimestamp() + '}'; } }
(2)水印对象
public class WeixinWaterMark { private Long timestamp; private String appid; public Long getTimestamp() { return timestamp; } public void setTimestamp(Long timestamp) { this.timestamp = timestamp; } public String getAppid() { return appid; } public void setAppid(String appid) { this.appid = appid; } }
2、解密工具类
import java.nio.charset.StandardCharsets; import java.security.*; import java.security.spec.InvalidParameterSpecException; import java.util.Base64; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import com.alibaba.fastjson.JSON; import entity.WeixinPhoneDecryptInfo; import org.bouncycastle.jce.provider.BouncyCastleProvider; public class AESForWeixinGetPhoneNumber { //加密方式 private static String keyAlgorithm = "AES"; //避免重复new生成多个BouncyCastleProvider对象,因为GC回收不了,会造成内存溢出 //只在第一次调用decrypt()方法时才new 对象 private static boolean initialized = false; //用于Base64解密 private Base64.Decoder decoder = Base64.getDecoder(); //待解密的数据 private String originalContent; //会话密钥sessionKey private String encryptKey; //加密算法的初始向量 private String iv; public AESForWeixinGetPhoneNumber(String originalContent,String encryptKey,String iv) { this.originalContent = originalContent; this.encryptKey = encryptKey; this.iv = iv; } /** * AES解密 * 填充模式AES/CBC/PKCS7Padding * 解密模式128 * * @return 解密后的信息对象 */ public WeixinPhoneDecryptInfo decrypt() { initialize(); try { //数据填充方式 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); Key sKeySpec = new SecretKeySpec(decoder.decode(this.encryptKey), keyAlgorithm); // 初始化 cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(decoder.decode(this.iv))); byte[]data = cipher.doFinal(decoder.decode(this.originalContent)); String datastr = new String(data, StandardCharsets.UTF_8); return JSON.toJavaObject(JSON.parseObject(datastr),WeixinPhoneDecryptInfo.class); } catch (Exception e) { System.out.println(e.getMessage()); return null; } } /**BouncyCastle作为安全提供,防止我们加密解密时候因为jdk内置的不支持改模式运行报错。**/ private static void initialize() { if (initialized) return; Security.addProvider(new BouncyCastleProvider()); initialized = true; } // 生成iv private static AlgorithmParameters generateIV(byte[] iv) throws NoSuchAlgorithmException, InvalidParameterSpecException { AlgorithmParameters params = AlgorithmParameters.getInstance(keyAlgorithm); params.init(new IvParameterSpec(iv)); return params; } }
3、涉及到jar包
<dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.61</version> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk16</artifactId> <version>1.46</version> </dependency>
4、测试类
public class AEStest { public static void main(String[] args) { String encryptedData="加密的敏感数据"; String iv="初始向量"; String appId="小程序id"; AESForWeixinGetPhoneNumber aes=new AESForWeixinGetPhoneNumber(encryptedData,sessionKey,iv); WeixinPhoneDecryptInfo info=aes.decrypt(); if (null==info){ System.out.println("error"); }else { if (!info.getWeixinWaterMark().getAppid().equals(appId)){ System.out.println("wrong appId"); } System.out.println(info.toString()); } } }