java实现微信小程序获取并解密用户数据(前台+后台)

  • Post author:
  • Post category:java


一、概述

微信推出了小程序,很多公司的客户端应用不仅具有了APP、H5、还接入了小程序开发。但是,小程序中竟然没有提供Java版本的加密数据解密算法。这着实让广大的Java开发人员蛋疼。

微信小程序提供的加密数据解密算法链接为:https://mp.weixin.qq.com/debug/wxadoc/dev/api/signature.html

最新地址为:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html

二、实小程序端的实现(小程序app.js)

doLogin(scene) {
    wx.showLoading({
      title: '加载中...',
    })
    var _this = this;
    wx.login({
      success: function (loginRes) {
        if (loginRes) {
          //获取用户信息
          wx.getUserInfo({
            success: function (infoRes) {
              console.log('===开始request请求');
              //请求服务端的登录接口
              wx.request({
                url: _this.globalData.url + '/v1/api/login',
                data: {
                  code: loginRes.code,//临时登录凭证
                  rawData: infoRes.rawData,//用户非敏感信息
                  signature: infoRes.signature,//签名
                  encrypteData: infoRes.encryptedData,//用户敏感信息
                  iv: infoRes.iv,//解密算法的向量
                  scene: _this.globalData.scene
                },
                success: function (res) {
                  res = res.data;
                  wx.hideLoading();
                  if (res.code == 1) {
                    console.log('登录成功!');
                    wx.setStorageSync('userInfo', res.data);
                    wx.navigateBack({
                      delta: -1
                    });
                  } else {
                    console.log('登录失败!');
                  }
                },
                fail: function (error) {
                  //调用服务端登录接口失败
                  console.log(error);
                }
              });
            }
          });
        } else {

        }
      }
    });
  }

三、实现Java版本的微信小程序加密数据解密算法

package com.api.controller.wx;

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.Arrays;
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 org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.codehaus.xfire.util.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.api.entity.User;
import com.api.service.UserService;
import com.api.utils.Constant;
import com.api.utils.HttpSenderUtil;
import com.api.utils.Result;
import com.api.utils.StringUtils;

@RequestMapping("/v1/api")
@Controller
public class WxLoginController {
	
    @Autowired
    private UserService userService;

	@RequestMapping("/login")
	@ResponseBody
	public Result<Map<String,Object>> doLogin(Model model,
	                                  @RequestParam(value = "code",required = false) String code,
	                                  @RequestParam(value = "rawData",required = false) String rawData,
	                                  @RequestParam(value = "signature",required = false) String signature,
	                                  @RequestParam(value = "encrypteData",required = false) String encrypteData,
	                                  @RequestParam(value = "iv",required = false) String iv,
	                                  @RequestParam(value = "scene",required = false) String scene){
	 
	    //System.out.println("用户非敏感信息"+rawData);
	    JSONObject rawDataJson = JSON.parseObject( rawData );
	    //System.out.println("签名"+signature);
	    JSONObject SessionKeyOpenId = getSessionKeyOrOpenId( code );
	    //System.out.println("SessionAndopenId="+SessionKeyOpenId);
	    String openId = SessionKeyOpenId.getString("openid" );
	    String sessionKey = SessionKeyOpenId.getString( "session_key" );
	    //System.out.println("openid="+openId+",session_key="+sessionKey);

	    Map<String,Object> mapUser = userService.findByOpenid(openId);
	    User user = new User();
	    if(mapUser==null){
	        String nickName = rawDataJson.getString( "nickName" );
	        String avatarUrl = rawDataJson.getString( "avatarUrl" );
	        String gender  = rawDataJson.getString( "gender" );
	        String city = rawDataJson.getString( "city" );
	        String country = rawDataJson.getString( "country" );
	        String province = rawDataJson.getString( "province" );
	 
	        user.setOpenId(openId);
	        user.setSessionKey(sessionKey);
	        user.setuName(nickName);
	        user.setuGender(gender);
	        user.setuAddress(country+" "+province+" "+city);
	        user.setuAvatar(avatarUrl);
	        user.setIsSys("0");
	        user.setActivityNum("3");
	        user.setuExtensionQr("");
	        user.setuExtensionId(scene);
	        user.setCreateTime(StringUtils.newDate());
	        user = userService.save( user );
	    }else {
	        System.out.println("用户已存在");
	        user.setuId(mapUser.get("U_ID").toString());
	        user.setIsSys(mapUser.get("IS_SYS").toString());
	    }

	    JSONObject userInfo = getUserInfo( encrypteData, sessionKey, iv );
	    userInfo.put("uId", user.getuId());
	    userInfo.put("isSys", user.getIsSys());
	    System.out.println("根据解密算法获取的userInfo="+userInfo);
	    return Result.success(userInfo);
	}
	
	public static JSONObject getSessionKeyOrOpenId(String code){
	    //微信端登录code
	    String wxCode = code;
	    String requestUrl = "https://api.weixin.qq.com/sns/jscode2session?appid="+Constant.APP_ID+"&secret="+Constant.APP_SECRET+"&js_code="+wxCode+"&grant_type=authorization_code";
	    //发送post请求读取调用微信接口获取openid用户唯一标识
	    JSONObject jsonObject = JSON.parseObject( HttpSenderUtil.sendPost( requestUrl,null ));
	    return jsonObject;
	}
	
	public static 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 JSON.parseObject(result);
	        }
	    } catch (NoSuchAlgorithmException e) {
	       System.out.println(e.getMessage());
	    } catch (NoSuchPaddingException e) {
	    	System.out.println(e.getMessage());
	    } catch (InvalidParameterSpecException e) {
	    	System.out.println(e.getMessage());
	    } catch (IllegalBlockSizeException e) {
	    	System.out.println(e.getMessage());
	    } catch (BadPaddingException e) {
	    	System.out.println(e.getMessage());
	    } catch (UnsupportedEncodingException e) {
	    	System.out.println(e.getMessage());
	    } catch (InvalidKeyException e) {
	    	System.out.println(e.getMessage());
	    } catch (InvalidAlgorithmParameterException e) {
	    	System.out.println(e.getMessage());
	    } catch (NoSuchProviderException e) {
	    	System.out.println(e.getMessage());
	    }
	    return null;
	}
	
}

四、使用

将app.js中的代码复制进app.js,然后调用方法登录即可!

注意修改其中的链接以及appid和appsecret

补充:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.56</version>
</dependency>



版权声明:本文为jiaqu2177原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。