微信小程序 对微信用户数据的签名验证和加解密 Java版

好久没写博客了,今天部门小兄弟来问微信小程序 怎么对微信服务器传过来的用户数据解密,进而获得openid和昵称头像等。网上的资料不多,不得不说腾讯太喜欢PHP了,demo好多都是PHP版本的。

这里是腾讯相关API:https://mp.weixin.qq.com/debug/wxadoc/dev/api/signature.html


自己翻译了下PHP版本的,也顺便发到博客上,以让后来的同学活得容易点。

用到maven依赖:

<dependency>
			<groupId>commons-codec</groupId>
			<artifactId>commons-codec</artifactId>
			<version>1.9</version>
		</dependency>
<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.1.32</version>
		</dependency>
 <dependency>
	      <groupId>org.bouncycastle</groupId>
	      <artifactId>bcprov-jdk15on</artifactId>
	      <version>1.55</version>
	    </dependency>
AES工具类:

/*
 * 文件名:AESUtils.java
 * 版权:
 * 描述:
 * 修改人:Awoke
 * 修改时间:2018-1-24
 * 跟踪单号:
 * 修改单号:
 * 修改内容:
 */

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Security;

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;


/**
 *
 * @author Awoke
 * @version 2018-1-24
 * @see AESUtils
 * @since
 */
public class AESUtils
{
    public static boolean initialized = false;

    /**  
     * AES解密  
     * @param content 密文  
     * @return  
     * @throws InvalidAlgorithmParameterException   
     * @throws NoSuchProviderException   
     */
    public static byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte)
        throws InvalidAlgorithmParameterException
    {
        initialize();
        try
        {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            Key sKeySpec = new SecretKeySpec(keyByte, "AES");

            cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化     
            byte[] result = cipher.doFinal(content);
            return result;
        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        catch (NoSuchPaddingException e)
        {
            e.printStackTrace();
        }
        catch (InvalidKeyException e)
        {
            e.printStackTrace();
        }
        catch (IllegalBlockSizeException e)
        {
            e.printStackTrace();
        }
        catch (BadPaddingException e)
        {
            e.printStackTrace();
        }
        catch (NoSuchProviderException e)
        {
            // TODO Auto-generated catch block    
            e.printStackTrace();
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block    
            e.printStackTrace();
        }
        return null;
    }

    public static void initialize()
    {
        if (initialized) return;
        Security.addProvider(new BouncyCastleProvider());
        initialized = true;
    }

    /**
     * 生成iv
     * @param iv
     * @return
     * @throws Exception 
     * @see
     */
    public static AlgorithmParameters generateIV(byte[] iv)
        throws Exception
    {
        AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
        params.init(new IvParameterSpec(iv));
        return params;
    }

}
WXBizDataCrypt.java

/*
 * 文件名:WXBizDataCrypt.java
 * 版权:
 * 描述:
 * 修改人:Awoke
 * 修改时间:2018-1-24
 * 跟踪单号:
 * 修改单号:
 * 修改内容:
 */

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sinocjh.bp.security.AESUtils;


/**
 * 对微信小程序用户加密数据的解密示例代码.
 * @author Awoke
 * @version 2018-1-24
 * @see WXBizDataCrypt
 * @since
 */
public class WXBizDataCrypt
{

    private String appid;

    private String sessionKey;

    public WXBizDataCrypt(String appid, String sessionKey)
    {
        this.appid = appid;
        this.sessionKey = sessionKey;
    }

    /**
     * 检验数据的真实性,并且获取解密后的明文.
     * @param encryptedData string 加密的用户数据
     * @param iv string 与用户数据一同返回的初始向量
     *
     * @return data string 解密后的原文
     */
    public String decryptData(String encryptedData, String iv)
    {
        if (StringUtils.length(sessionKey) != 24)
        {
            return "ErrorCode::$IllegalAesKey;";
        }
        // 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
        byte[] aesKey = Base64.decodeBase64(sessionKey);

        if (StringUtils.length(iv) != 24)
        {
            return "ErrorCode::$IllegalIv;";
        }
        // 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。
        byte[] aesIV = Base64.decodeBase64(iv);

        // 对称解密的目标密文为 Base64_Decode(encryptedData)
        byte[] aesCipher = Base64.decodeBase64(encryptedData);

        Map<String, String> map = new HashMap<>();

        try
        {
            byte[] resultByte = AESUtils.decrypt(aesCipher, aesKey, aesIV);

            if (null != resultByte && resultByte.length > 0)
            {
                String userInfo = new String(resultByte, "UTF-8");
                map.put("code", "0000");
                map.put("msg", "succeed");
                map.put("userInfo", userInfo);
                
                // watermark参数说明:
                // 参数  类型  说明
                // watermark   OBJECT  数据水印
                // appid   String  敏感数据归属appid,开发者可校验此参数与自身appid是否一致
                // timestamp   DateInt 敏感数据获取的时间戳, 开发者可以用于数据时效性校验'
                
                // 根据微信建议:敏感数据归属appid,开发者可校验此参数与自身appid是否一致
                // if decrypted['watermark']['appid'] != self.appId:
                JSONObject jsons = JSON.parseObject(userInfo);
                String id = jsons.getJSONObject("watermark").getString("appid");
                if(!StringUtils.equals(id, appid))
                {
                    return "ErrorCode::$IllegalBuffer;";
                }
            }
            else
            {
                map.put("status", "1000");
                map.put("msg", "false");
            }
        }
        catch (InvalidAlgorithmParameterException e)
        {
            e.printStackTrace();
        }
        catch (UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }

        return JSON.toJSONString(map);
    }

    /**
     *  
     * @param args 
     * @see 
     */
    public static void main(String[] args)
    {
        String appId = "wx4f4bc4dec97d474b";
        String sessionKey = "tiihtNczf5v6AKRyjwEUhQ==";
        String encryptedData = "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZM"
                               + "QmRzooG2xrDcvSnxIMXFufNstNGTyaGS"
                               + "9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+"
                               + "3hVbJSRgv+4lGOETKUQz6OYStslQ142d"
                               + "NCuabNPGBzlooOmB231qMM85d2/fV6Ch"
                               + "evvXvQP8Hkue1poOFtnEtpyxVLW1zAo6"
                               + "/1Xx1COxFvrc2d7UL/lmHInNlxuacJXw"
                               + "u0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn"
                               + "/Hz7saL8xz+W//FRAUid1OksQaQx4CMs"
                               + "8LOddcQhULW4ucetDf96JcR3g0gfRK4P"
                               + "C7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB"
                               + "6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns"
                               + "/8wR2SiRS7MNACwTyrGvt9ts8p12PKFd"
                               + "lqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYV"
                               + "oKlaRv85IfVunYzO0IKXsyl7JCUjCpoG"
                               + "20f0a04COwfneQAGGwd5oa+T8yO5hzuy" + "Db/XcxxmK01EpqOyuxINew==";
        String iv = "r7BXXKkLb8qrSNn05n0qiA==";

        WXBizDataCrypt biz = new WXBizDataCrypt(appId, sessionKey);
        
        System.out.println(biz.decryptData(encryptedData, iv));

    }
}
代码细节需要优化下,不是最优,请自处理。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值