美文网首页小程序微信小程序
微信小程序获取用户信息,解密encryptedData

微信小程序获取用户信息,解密encryptedData

作者: Sonny721 | 来源:发表于2017-03-24 01:00 被阅读8425次

    标签:微信小程序 用户信息
    小程序中,通过调用微信API(wx.getUserInfo)可以或得到当前用户的微信信息(此处会弹出获取信息授权框),但是仅有用户的基本信息,比如头像、昵称、性别等,由于产品业务需要,需要得到当前用户的openid以及unionId(微信开放平台下用户的唯一标识),那如何获取?其实微信的API(wx.getUserInfo)中,已经给到这两组数据,只是为了安全,没有在明文中显示,而是在wx.getUserInfo方法的结果参数encryptedData 中,只要将参数encryptedData 进行解密,就可以得到想要的数据,官方没有给到Java的解密过程,下面是Java版的解密过程:

    package com.boboqi.wx.userinfo;
    import java.io.UnsupportedEncodingException;
    import java.security.AlgorithmParameters;
    import java.security.InvalidAlgorithmParameterException;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    import java.security.Security;
    import java.security.spec.InvalidParameterSpecException;
    import java.util.HashMap;
    import java.util.Map;
    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 net.sf.json.JSONObject;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.util.Arrays;
    import org.codehaus.xfire.util.Base64;
    import com.boboqi.wx.common.RemoteInterfaceAddress;
    import com.boboqi.wx.util.HttpsClientUtil;
    /**
     * 微信小程序信息获取
     * @author songhn
     */
    public class WXAppletUserInfo {
        /**
         * 获取微信小程序 session_key 和 openid
         */
        public JSONObject getSessionKeyAndOropenid(String code){
            //微信端登录code值
            String wxCode = code;
            String requestUrl = WxappConfig.GETSESSIONKEYOROPENID;
            Map<String,String> requestUrlParam = new HashMap<String,String>();
            requestUrlParam.put("appid", RemoteInterfaceAddress.AppletAPPID);
            requestUrlParam.put("secret", RemoteInterfaceAddress.AppletAppSecret);
            requestUrlParam.put("js_code", wxCode);
            requestUrlParam.put("grant_type", "authorization_code");
            JSONObject jsonObject = HttpsClientUtil.getInstance().sendGetRequest(requestUrl, requestUrlParam);
            return jsonObject;
        }
        /**
         * 解密用户敏感数据获取用户信息
         * @param sessionKey 数据进行加密签名的密钥
         * @param encryptedData 包括敏感数据在内的完整用户信息的加密数据
         * @param iv 加密算法的初始向量
         */
        public JSONObject getUserInfo(String encryptedData,String sessionKey,String iv){
            // 被加密的数据
            byte[] dataByte = Base64.decode(encryptedData);
            // 加密秘钥
            byte[] keyByte = Base64.decode(sessionKey);
            // 偏移量
            byte[] ivByte = Base64.decode(iv);
            try {
                // 如果密钥不足16位,那么就补足.  这个if 中的内容很重要
                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;
                }
                // 初始化
                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(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
                byte[] resultByte = cipher.doFinal(dataByte);
                if (null != resultByte && resultByte.length > 0) {
                    String result = new String(resultByte, "UTF-8");
                    return JSONObject.fromObject(result);
                }
            }catch (NoSuchProviderException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    附:微信小程序加密数据解密算法

    接口如果涉及敏感数据(如wx.getUserInfo
    当中的 openId 和unionId ),接口的明文内容将不包含这些敏感数据。开发者如需要获取敏感数据,需要对接口返回的加密数据( encryptedData )进行对称解密。 解密算法如下:
    对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
    对称解密的目标密文为 Base64_Decode(encryptedData)。
    对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
    对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。
    另外,为了应用能校验数据的有效性,我们会在敏感数据加上数据水印( watermark )

    相关文章

      网友评论

      • 續冩:javax.crypto.BadPaddingException: pad block corrupted
        at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(Unknown Source)
        at javax.crypto.Cipher.doFinal(Cipher.java:2165)
        at com.xinlong.rent.tools.AES2.getUserInfo(AES2.java:73)
        at com.xinlong.rent.tools.AES2.main(AES2.java:96)
        用了你这例子,怎么报错呀?
      • 408b6f244d10:部署到服务器上,报错
        java.lang.SecurityException: JCE cannot authenticate the provider BC
        at javax.crypto.Cipher.getInstance(Cipher.java:656)
        at javax.crypto.Cipher.getInstance(Cipher.java:595)
      • ff6ef1d66af4:解密很慢,不知道是啥原因,每次到这里“Arrays.fill(temp, (byte) 0);”就一直卡住。

      本文标题:微信小程序获取用户信息,解密encryptedData

      本文链接:https://www.haomeiwen.com/subject/akdxottx.html