吐血记录微信小程序授权获取Unionid及linux下使用bouncycastle解密用户数据 遇到的坑

背景

公司小程序上线了,发现系统无法拿到一些用户的UniondID。但是上线前的测试一切都是正常的。

坑1

经排查,发现一些用户通过下面的接口无法得到unionid

https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code

阅读https://developers.weixin.qq.com/miniprogram/dev/api/uinionID.html 得知,从未在关联公众号或小程序进行授权过的用户,是不会直接返回unionid的。要拿到这些用户的unionid需要以下3个数据

1.https://api.weixin.qq.com/sns/jscode2session返回的session_key

2. wx.getUserInfo且用户同意后返回的encryptedData和iv

使用以下代码可以解密出用户的信息



import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.io.UnsupportedEncodingException;
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.NoSuchProviderException;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class AES {
    public static boolean initialized = false;

    public static void main(String[] args) throws InvalidAlgorithmParameterException, UnsupportedEncodingException {
        String encryptedData = "";
        String iv = "";
        String sessionKey = "";

        byte[] resultByte = AES.decrypt(Base64.decodeBase64(encryptedData),
                Base64.decodeBase64(sessionKey),
                Base64.decodeBase64(iv));
        System.out.println(new String(resultByte,"utf-8"));
    }

    /**
     * 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 (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

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

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

}  

坑2,真正吐血的地方

使用以上的方法在我本机上面进行测试是没问题的,但是将项目部署上Linux上之后又出了一个问题

解密的时候抛异常:

java.security.NoSuchAlgorithmException - Cannot find any provider supporting AES/CBC/PKCS7Padding

我回头看代码,要实现在java端用PKCS7Padding填充,需要用到bouncycastle组件来实现,解密代码中确实也设置了。且本机也是可以解密的,本机和linux上的jdk均是官网下载的1.8版本,为什么Linux上就不行呢

//使用BouncyCastleProvider组件填充
Security.addProvider(new BouncyCastleProvider());

maven中也引用了bouncycastle


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

排除代码问题的话很明显是环境问题了,linux上使用Security.addProvider(new BouncyCastleProvider());  不起效果。。。

那没办法了,只能手动改jre。步骤如下

1.把bcprov-jdk15on-1.59.jar 复制到jre目录中的/lib/ext

2.编辑/lib/security/java.security

....
security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
security.provider.3=sun.security.ec.SunEC
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider
security.provider.8=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.9=sun.security.smartcardio.SunPCSC

#在此加上这句代码
security.provider.x=org.bouncycastle.jce.provider.BouncyCastleProvider

.....

3.重启tomcat,解密成功了。。。

附一份检测是否支持bouncycastle的代码。方法:

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import java.security.Security;
public class TestB {

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        System.out.println("Attemptingto get a Cipher and encrypt...");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        System.out.println("OK");
    }
}

如果想用纯Js解密也是可以的,这里有一篇文章:https://www.cnblogs.com/cai-rd/p/6816849.html

原文地址:https://www.cnblogs.com/valu/p/10699760.html

时间: 2024-12-13 14:16:36

吐血记录微信小程序授权获取Unionid及linux下使用bouncycastle解密用户数据 遇到的坑的相关文章

微信小程序授权页面

微信小程序授权页面,效果图如下 app.js  中的 onLaunch或onShow中加如下代码,如果没授权跳转到授权页面 // 获取用户信息 wx.getSetting({ success: res => { if (res.authSetting['scope.userInfo']) { // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 wx.getUserInfo({ success: res => { // 可以将 res 发送给后台解码出 unionId

微信小程序如何获取openid

微信小程序如何获取openid wx.login({ success: res => { // 发送 res.code 到后台换取 openId, sessionKey, unionId // console.log(res) var appid = 'wxbe08efce713a44bf'; //填写微信小程序appid var secret = 'd65ad3d9ee159c568200c30a3bb49baf'; //填写微信小程序secret //调用request请求api转换登录凭证

完整微信小程序授权登录页面教程

完整微信小程序授权登录页面教程 1.前言 微信官方对getUserInfo接口做了修改,授权窗口无法直接弹出,而取而代之是需要创建一个button,将其open-type属性绑定getUseInfo方法.在参考了网路上各种方案之后,实现了用户在授权之后跳转到小程序首页的授权登录页面. 2.实现效果 3.实现思路 在进入小程序时先对授权情况进行判断,若已经过授权则直接跳转到首页,若还未经过授权则进入授权页面,点击页面的授权按钮会弹出选择框,选择"拒绝"则不进行跳转,选择"允许&

微信小程序无法获取到unionId(专业踩坑20年)

UnionID机制说明如果开发者拥有多个移动应用.网站应用.和公众帐号(包括小程序),可通过unionid来区分用户的唯一性,因为只要是同一个微信开放平台帐号下的移动应用.网站应用和公众帐号(包括小程序),用户的unionid是唯一的.换句话说,同一用户,对同一个微信开放平台下的不同应用,unionid是相同的. 我们系统都做了移动应用.网站应用.和公众帐号的微信登入,我们后端这边是有微信绑定账号功能的.所以需要在微信的给出的用户唯一的unionID判断该用户是否已绑定微信号. 微信小程序API

微信小程序:获取地理定位和显示相应的城市名称。

最近在看微信小程序,遇到地理定位显示城市名称的问题.本文就是记录这一过程. 解决方案                                                                                                                                               小程序的wx.getLocation()获得是经纬度并不包含地名,所以要通过经纬度用相应的地图转换出地名(本文使用的是百度地图).

微信小程序【获取验证码】倒计时效果

最近开始接触微信小程序,会记录一些相关的小功能--例如这次是点击[获取验证码]按钮出现的倒计时效果. 原文: http://blog.csdn.net/Wu_shuxuan/article/details/78539075  感谢 .wxml <button class="buttonget" disabled='{{disabled}}' data-id="2" bindtap="getVerificationCode"> {{ti

微信小程序实现获取用户信息并存入数据库操作示例

微信小程序获取用户信息简单,但是在存入自己服务器数据库的过程中研究了一天多的时间,并且网上搜索不到该资源,故发出来供大家参考. index.js ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 Page({  data: {   nickNam

微信小程序 授权登录详解(附完整源码)

一.前言 由于微信官方修改了 getUserInfo 接口,所以现在无法实现一进入微信小程序就弹出授权窗口,只能通过 button 去触发. 官方连接:https://developers.weixin.qq.com/community/develop/doc/0000a26e1aca6012e896a517556c01 二.实现思路 自己写一个微信授权登录页面让用户实现点击的功能,也就是实现了通过 button 组件去触发 getUserInof 接口.在用户进入微信小程序的时候,判断用户是否

微信小程序实例-获取当前的地理位置、速度

微信小程序官方文档 https://mp.weixin.qq.com/debug/wxadoc/dev/api/location.html JS代码 //index.js //获取应用实例 var app = getApp() Page({ data: { motto: '示例小程序-获取当前地理位.速度', userInfo: {}, hasLocation:false, location:{} }, //事件处理函数 bindViewTap: function() { wx.navigate