评论

同城配送排坑贴,打工人永不加班!

对接小程序最新功能同城配送,小程序加密接口实践排坑贴,一步一步按步就班地来,你也可以提前下班!!

同城配送,微信最新出炉的,微信官方对接好多个运力方,价格会稍微低一点,我们只需要充值就可以使用了,但是因为是新出的,文档还是在线文档,而且比较绕,看讨论组里面比较多人也遇到坑,我对接完了就细细盘点一下吧,废话不多说,开搞!

同城配送产品介绍:https://docs.qq.com/doc/DVWRCSGllWWZBbG9t

同城配送API文档:https://doc.weixin.qq.com/doc/w3_ADkAtAZ1ACchtE1J1bXRzGqhpUnYX?scode=AJEAIQdfAAoySHzTsMADkAtAZ1ACc

官方加解密教程Demo:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.html

我用的开发语言是JAVA!!其他语言的兄弟姐妹们可以借鉴一下找找思路,本帖我是调用同城配送的查询店铺接口

第1⃣️坑:错误代码:934011, 错误信息:request_body is required

这个是因为接口需要进行加密传输,如果请求头Header不带这几个参数的话就会报这个错,appid和timestamp参数的话还好说,signature这个需要后续通过不同参数拼接进行base64才可以计算出来(后面会贴代码)

第2⃣️坑:签名失败{"errcode": 40234,"errmsg": "invalid signature rid: 64b0c114-748bb871-181713e7"}

这个也是比较头疼的,也是比较多人遇到的错误,原因是加密出来的签名有问题。

加密需要拿到 对称密钥和 非对称密钥 登录小程序后台-开发管理-》开发设置-》API安全

贴图:非对称的密文只有在初始化的时候可以下载(已经开启了的可以按修改,保存前下载,确保下载回来的是----BEGIN PRIVATE KEY----开头的,因为官方前两天有bug,点击下载回来的还是非对称明文,不过腾讯已经说让相关人员去优化了)

我暂且给这几个参数取名ABCD,方便后续看代码!

直接贴数据加密的代码:代码是官方给出的加密demo,这里比较简单,直接看代码,按照上图的ABCD对好入座

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

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;

import com.google.gson.Gson;
import com.google.gson.JsonObject;

public class AES_Enc {
    private static JsonObject getReqForSign(JsonObject ctx, JsonObject req) {
        Gson gson = new Gson();
        // 开发者本地信息
        String local_appid = ctx.get("local_appid").getAsString();
        String url_path = ctx.get("url_path").getAsString();
        String local_sym_sn = ctx.get("local_sym_sn").getAsString();
        String local_sym_key = ctx.get("local_sym_key").getAsString();
        //加密签名使用的统一时间戳
        long localTs = System.currentTimeMillis() / 1000;
        String nonce = generateNonce();

        req.addProperty("_n", nonce);
        req.addProperty("_appid", local_appid);
        req.addProperty("_timestamp", localTs);
        String plaintext = gson.toJson(req);

        String aad = url_path + "|" + local_appid + "|" + localTs + "|" + local_sym_sn;
        byte[] realKey = Base64.getDecoder().decode(local_sym_key);
        byte[] realIv = generateRandomBytes(12);
        byte[] realAad = aad.getBytes(StandardCharsets.UTF_8);
        byte[] realPlaintext = plaintext.getBytes(StandardCharsets.UTF_8);

        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            SecretKeySpec keySpec = new SecretKeySpec(realKey, "AES");
            GCMParameterSpec parameterSpec = new GCMParameterSpec(128, realIv);
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, parameterSpec);
            cipher.updateAAD(realAad);

            byte[] ciphertext = cipher.doFinal(realPlaintext);
            byte[] encryptedData = Arrays.copyOfRange(ciphertext, 0, ciphertext.length - 16);
            byte[] authTag = Arrays.copyOfRange(ciphertext, ciphertext.length - 16, ciphertext.length);

            String iv = base64Encode(realIv);
            String data = base64Encode(encryptedData);
            String authtag = base64Encode(authTag);


            JsonObject reqData = new JsonObject();
            reqData.addProperty("iv", iv);
            reqData.addProperty("data", data);
            reqData.addProperty("authtag", authtag);


            JsonObject reqforsign = new JsonObject();
            reqforsign.addProperty("req_ts", localTs);
            reqforsign.addProperty("req_data", reqData.toString());

            return reqforsign;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    private static String generateNonce() {
        byte[] nonce = generateRandomBytes(16);
        return base64Encode(nonce).replace("=", "");
    }

    private static byte[] generateRandomBytes(int length) {
        byte[] bytes = new byte[length];
        new SecureRandom().nextBytes(bytes);
        return bytes;
    }

    private static String base64Encode(byte[] data) {
        return Base64.getEncoder().encodeToString(data);
    }

    private static JsonObject getCtx() {
        JsonObject ctx = new JsonObject();
        // 仅做演示,敏感信息请勿硬编码
        ctx.addProperty("local_sym_key", "YcMLjYryM9L3I*************+W3dUZDm6Fj8=");
        ctx.addProperty("local_sym_sn", "6bda832d********ba2c5c072df");
        ctx.addProperty("local_appid", "wx55e9*******d09");
        ctx.addProperty("url_path", "https://api.weixin.qq.com/cgi-bin/express/intracity/querystore");

        return ctx;
    }

    private static JsonObject getRawReq() {
        JsonObject req = new JsonObject();
        req.addProperty("wx_store_id", "40000000************");
        return req;
    }

    public static void main(String[] args) {
        JsonObject req = getRawReq();
        JsonObject ctx = getCtx();
        JsonObject reqforsign = getReqForSign(ctx, req);
        if (reqforsign != null) {
            System.out.println(reqforsign.get("req_ts").getAsLong());
            System.out.println(reqforsign.get("req_data").getAsString());
        }
    }

    public static JsonObject getData() {
        JsonObject req = getRawReq();
        JsonObject ctx = getCtx();
        JsonObject reqforsign = getReqForSign(ctx, req);
        return reqforsign;
    }
}




代码参数说明如图,此时执行main方法打印如下:

OK!到此请求参数的加密就有了,加下来就到请求头的签名了。

第3⃣️坑:非对称加密的私钥

我们直接下载回来的PRIVATE KEY是不能够直接使用的,直接使用签名的时候会报错:java.lang.IllegalArgumentException: Illegal base64 character 2d

官方也有说明:需要转换一下

具体操作:

将下载回来的私钥改一下名:我们改成:private_key.pem

在私钥的当前路径打开终端

先执行:

openssl rsa -in private_key.pem -outform der -out private_key.der

再执行:

openssl pkcs8 -topk8 -inform der -in private_key.der -outform pem -out private_key_pkcs8.pem -nocrypt


OK!现在我们得到了这三个

其中private_key_pkcs8.pem里面的内容我们就可以直接替换官方的demo代码了!!

废话不多说,直接上代码

// RSAwithSHA256

import com.google.gson.JsonObject;

import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.PSSParameterSpec;
import java.util.Base64;

public class RSA_Sign {
    public static String getSignature(JsonObject ctx, JsonObject req) {
        String signatureBase64 = null;
        // 开发者本地信息
        String local_appid = ctx.get("local_appid").getAsString();
        String url_path = ctx.get("url_path").getAsString();
        String local_sym_sn = ctx.get("local_sym_sn").getAsString();
        String local_private_key = ctx.get("local_private_key").getAsString();
        // 待请求API数据
        long reqTs = req.get("req_ts").getAsLong();
        String reqData = req.get("req_data").getAsString();

        String payload = url_path + "\n" + local_appid + "\n" + reqTs + "\n" + reqData;
        byte[] dataBuffer = payload.getBytes(StandardCharsets.UTF_8);
        try {
            local_private_key = local_private_key.replace("-----BEGIN PRIVATE KEY-----", "");
            local_private_key = local_private_key.replace("-----END PRIVATE KEY-----", "");
            local_private_key = local_private_key.replaceAll("\\s+", "");
            byte[] decoded = Base64.getDecoder().decode(local_private_key);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decoded);
            RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(keySpec);
            Signature signature = Signature.getInstance("RSASSA-PSS");
            // salt长度,需与SHA256结果长度(32)一致
            PSSParameterSpec pssParameterSpec = new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 32, 1);
            signature.setParameter(pssParameterSpec);
            signature.initSign(priKey);
            signature.update(dataBuffer);
            byte[] sigBuffer = signature.sign();
            signatureBase64 = Base64.getEncoder().encodeToString(sigBuffer);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return signatureBase64;
        /*
        最终请求头字段
        {
            "Wechatmp-Appid": local_appid,
            "Wechatmp-TimeStamp": req_ts,
            "Wechatmp-Signature": sig,
        }
        */
    }

    private static JsonObject getReq() {
        JsonObject req = new JsonObject();
        req.addProperty("req_ts", 1689259852);
        req.addProperty("req_data", "{\"iv\":\"EehrptDmV/5gxjUT\",\"data\":\"zHlBtadb+dfEHwk4x1c4GZdz1MDSDV/3CAy4qYuMdkkxPOXDiQfJZCxnjBjivKNwPAZfKZZh3nv/xQyM8ZYUL9VUHP4M2kAcOMbvKLKnB7j4Lxwioiir4R+IHV7mwWNcL9SrztZ1FP9Nzg7kxc6xD2RrJkzPQ3W46w==\",\"authtag\":\"8Md6QGPY9HpPcLv86dkzyQ==\"}");
        return req;
    }

    private static JsonObject getCtx() {
        JsonObject ctx = new JsonObject();
        // 仅做演示,敏感信息请勿硬编码
        String localPrivateKey = "-----BEGIN PRIVATE KEY-----\n" +
                "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC971V5m8Ou/MO3\n" +
                "CEP9MP3tUXJu2fE25YbIFPysRx6SD7hXxCZjNRjQ6q7DENCpt2541v5IdJe3kd8K\n" +
                "y5oLVDyzcTx6hWnyCInbS3lZJ27aTTS7LesOf8120uU3ma0CbICRhSH/oLWx9DNj\n" +
                "hpQbQQjracja42VGEqHm/3YlTy6CX0ygfOQ36iuNTvOFErdCffWild9YOZe757l+\n" +
                "ivTg0hoYq+/WzTCf3F0dsqn7og0eX6AXILBLnqs29cwtc/ov9BdDUxhCuCxghpTn\n" +
                "Pdd/l7zYOZYfZZM80q2wZWqkbh+75eQ2YAwjw7pBz905DdnGCdoNj7cORE78lQnF\n" +
                "YuT8VqV2YErQDR6gPZ2KEEtA0paHxBIeuluWgQqfdMGQqsNjRC2l2+Mx2Ly6CjzR\n" +
                "w70X3Db5x3QCtVRYz8J5303lOcrjFG2uB4w6dRWrCRbnwdlxFbIMdMTG4QKBgQCP\n" +
                "8RDygSRXrQYpEgWk2GqaxuQSoM0uAw5qhYmV75MeV+ZnBp0ITMvYjfrN9j43U/rC\n" +
                "l+gjz/KhMrMrxfAcx60TkOhD3W/6xsdNf2wXczP4Gvev5iBmEGLu5IGs4rkh8/AA\n" +
                "r5VNg659CCIkJMivYpr0GHU+1/ql06ZXpae5UZxgyQKBgQDcQq5dJVsEe0ky5G2O\n" +
                "GYZ/EPzOBlD+KRJyPVNzwKZws7UlhnNApwwp76/9UR+2PPhl/g5om6oBGygIAYhw\n" +
                "mx9wZkb1T3+qT2xJ7QMPRKZXfkthmay/7yigGTVRU1DhqmYfY35G+bsg3EsdeyHS\n" +
                "J5VUJ83ecM67+q+1FBekTZa+iA==\n" +
                "-----END PRIVATE KEY-----";

        ctx.addProperty("local_private_key", localPrivateKey);
        ctx.addProperty("local_sym_sn", "e84cdda4*********0cee78f277");
        ctx.addProperty("local_appid", "wx55******94d09");
        ctx.addProperty("url_path", "https://api.weixin.qq.com/cgi-bin/express/intracity/querystore");
        return ctx;
    }


    public static String getSign(JsonObject data) {
        JsonObject req = data;
        JsonObject ctx = getCtx();
        String sign = getSignature(ctx, req);
        return sign;
    }

    public static void main(String[] args) {
        JsonObject req = getReq();
        JsonObject ctx = getCtx();
        String res = getSignature(ctx, req);
        System.out.println(res);

    }
}


代码说明:

执行main方法打印出来的就是加密签名了,放到请求头里面,如果这个main方法执行错误了,就是你的私钥有问题了

最后我们发起请求的参数都全了,去调用一下!!

上面是请求返回的响应,也是通过加密的内容,并且请求反应的请求头里面的内容我们也是需要用到的,解密获取返回内容的时候需要用到

请求返回结果解密,直接上代码

// AES256_GCM

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

import java.nio.charset.StandardCharsets;
import java.util.Base64;

import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

public class AES_Dec {
    public static Object getRealResp(JsonObject ctx, JsonObject resp) {
        byte[] decryptedBytes = null;
        // 开发者本地信息
        String local_appid = ctx.get("local_appid").getAsString();
        String url_path = ctx.get("url_path").getAsString();
        String local_sym_sn = ctx.get("local_sym_sn").getAsString();
        String local_sym_key = ctx.get("local_sym_key").getAsString();
        // API响应数据,解密只需要响应头时间戳与响应数据
        long respTs = resp.get("resp_ts").getAsLong();
        String respData = resp.get("resp_data").getAsString();

        JsonParser parser = new JsonParser();
        JsonElement resp_data = parser.parse(respData);
        String iv = resp_data.getAsJsonObject().get("iv").getAsString();
        String data = resp_data.getAsJsonObject().get("data").getAsString();
        String authtag = resp_data.getAsJsonObject().get("authtag").getAsString();
        // 构建AAD
        String aad = url_path + "|" + local_appid + "|" + respTs + "|" + local_sym_sn;
        // 拼接cipher和authtag
        byte[] dataBytes = Base64.getDecoder().decode(data);
        byte[] authtagBytes = Base64.getDecoder().decode(authtag);
        byte[] new_dataBytes = new byte[dataBytes.length + authtagBytes.length];
        System.arraycopy(dataBytes, 0, new_dataBytes, 0, dataBytes.length);
        System.arraycopy(authtagBytes, 0, new_dataBytes, dataBytes.length, authtagBytes.length);
        byte[] aadBytes = aad.getBytes(StandardCharsets.UTF_8);
        byte[] ivBytes = Base64.getDecoder().decode(iv);
        Object realResp = null;
        try {
            byte[] keyBytes = Base64.getDecoder().decode(local_sym_key);
            SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
            GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, ivBytes);
            cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmParameterSpec);
            cipher.updateAAD(aadBytes);
            try {
                decryptedBytes = cipher.doFinal(new_dataBytes);
            } catch (Exception e) {
                System.out.println("auth tag验证失败");
                return null;
            }

            // 解密结果
            String decryptedData = new String(decryptedBytes, StandardCharsets.UTF_8);
            JsonElement element = parser.parse(decryptedData);
            Gson gson = new Gson();
            realResp = gson.fromJson(element, Object.class);
            long localTs = System.currentTimeMillis() / 1000;
            // 安全检查,根据业务实际需求判断
            if (element.getAsJsonObject().get("_appid").getAsString() == local_appid // appid不匹配
                    || element.getAsJsonObject().get("_timestamp").getAsLong() != respTs // timestampWechatmp-TimeStamp不匹配
                    || localTs - element.getAsJsonObject().get("_timestamp").getAsLong() > 300 // 响应数据的时候与当前时间超过5分钟
            ) {
                System.out.println("安全字段校验失败");
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return realResp;

    }

    private static JsonObject getCtx() {
        JsonObject ctx = new JsonObject();
        // 仅做演示,敏感信息请勿硬编码
        ctx.addProperty("local_sym_key", "YcMLjYryM9L3IFg*********3dUZDm6Fj8=");
        ctx.addProperty("local_sym_sn", "6bda832d57b*******2c5c072df");
        ctx.addProperty("local_appid", "wx55*********d09");
        ctx.addProperty("url_path", "https://api.weixin.qq.com/cgi-bin/express/intracity/querystore");

        return ctx;
    }

    private static JsonObject getResp() {
        JsonObject resp = new JsonObject();
        String respData = "{\"iv\":\"QrZZqNdqxToexKwy\",\"data\":\"CfoqyhQ1oYg2zJ7tvqO4t5\\/KA2zUD33y2D3FIbFShkclYaONiLqROmG8CfHm0EXMADNcvp4EQuxKxrGZbVE97qrymbnpreTT\\/XQtly62A84KrGCLIqi8SF\\/jM75QFH6qEuwy32gSsl7sv2GxDSCdb4JkpFPmskjsZgP3z9vBFUPklTiJtLRDfy\\/MPg9sYT3eVFuD636NO01\\/NkYPAa9WUIIlbDlqk\\/O0xMgBdi84JwqtxW+VuRqSkge30EluRBoiH4j3ngCuK5JGqfPw1MFXL0e55V72iBsSa5fqHDnskl62pKUcR+\\/h4Znw7H5f3U5WnUtsKAzH3hg22+VIgUp5veLOw1PI94c9Ks5A26+4OWIh9wmgUuInZo20g1j50G8ENfNPVcDApSG0P\\/yKJZFAsQrvx2c+pU6sVllo+XTp4eoz2wCNrEedEZ\\/ism02GWmwTtgWALFIedib44fOyNuIfNWwXMg\\/ywzBN37Ercip7vI+Iyd+wPTCjB046wmZYSzVelLY5qc97X7jo6m8+np3VS+NHr09tNGmjG5L\\/FMHO99WuURJqSNdXB3swiOlVbtRCYwA4epzhhnv2b6TzYN9UOLw\",\"authtag\":\"n5OB+4ZdaQU\\/ZE6wE3GO2w==\"}";
        resp.addProperty("resp_ts", 1689266097);
        resp.addProperty("resp_data", respData);

        return resp;
    }

    public static void main(String[] args) {
        JsonObject resp = getResp();
        JsonObject ctx = getCtx();
        Object res = getRealResp(ctx, resp);
        System.out.println(res);
    }
}


替换一下这里的加密内容和响应时间戳执行即可!

我们执行一下main方法打印出来内容:


OK!大功告成,从请求的加密到结果的解密都完成了!!

具体封装的话大家可以自己去弄,最后贴一下发起请求的方法吧,

final String accessToken = this.getWxMaService(request.getWxAppId()).getAccessToken();
log.info("accessToken is =>{}", this.getWxMaService(request.getWxAppId()).getAccessToken());
final JsonObject data = AES_Enc.getData();
final Long reqTs = data.get("req_ts").getAsLong();
final String reqData = data.get("req_data").getAsString();
final String sign = RSA_Sign.getSign(data);
log.info("data is ={}", data);
final HttpResponse response = HttpRequest.post("https://api.weixin.qq.com/cgi-bin/express/intracity/querystore?access_token=" + accessToken)
        .header("Wechatmp-Appid", "wx5********4d09")
        .header("Wechatmp-TimeStamp", reqTs.toString())
        .header("Wechatmp-Signature", sign)
        .header("Content-Type", "application/json;charset=utf-8")
        .body(reqData)
        .execute();
final String respSign = response.header("Wechatmp-Signature");
final String respAppId = response.header("Wechatmp-Appid");
final String respTs = response.header("Wechatmp-TimeStamp");
final String respSerial = response.header("Wechatmp-Serial");
log.info("respSign is {}", respSign);
log.info("respAppId is {}", respAppId);
log.info("respTs is {}", respTs);
log.info("respSerial is {}", respSerial);
log.info("请求返回结果是:{}", response.body());






最后一次编辑于  2023-07-14  
点赞 12
收藏
评论

27 个评论

  • 川页
    川页
    06-06

    非常好

    06-06
    赞同
    回复
  • 🦀
    🦀
    04-26

    你好,请问下,这个价格是在哪里拿到的?

    04-26
    赞同
    回复
  • captain😼
    captain😼
    04-19

    是不是少了个延签的步骤??

    04-19
    赞同
    回复 1
    • 嘿⃝嘿⃝🐾
      嘿⃝嘿⃝🐾
      10-15
      这步是不是可以忽略?
      10-15
      回复
  • captain😼
    captain😼
    04-19

    大佬, 我一直报这个错,{"errcode":40237,"errmsg":"invalid Wechatmp-Appid match request rid: 6621f669-6845d9e3-71539882"} 到底用什么appid? 我的加密是用了开放平台的文件

    04-19
    赞同
    回复
  • Human_nature
    Human_nature
    03-27

    非常感谢,很有帮助。已经顺利对接完毕。

    使用wxJava微信工具,自定义了一个http-post Exector, 对 AES_Enc、RSA_Sign、AES_Dec稍作改造,动态配置密钥。

    03-27
    赞同
    回复
  • 阿灿
    阿灿
    02-21

    请问订单回调通知这块怎么处理的,我在下单时写了回调地址,然后下单成功,调用模拟订单变化接口后,微信上接收到服务通知,但程序上收不到消息

    02-21
    赞同
    回复 1
    • Human_nature
      Human_nature
      03-27
      检查一下 notifyurl的配置是否有问题,内网需要做穿透
      03-27
      回复
  • melody
    melody
    01-12

    流程走通了!

    01-12
    赞同
    回复 1
    • captain😼
      captain😼
      04-19
      大佬 我一直报这个错,{"errcode":40237,"errmsg":"invalid Wechatmp-Appid match request rid: 6621f669-6845d9e3-71539882"} 到底用什么appid? 我的加密是用了开放平台的文件
      04-19
      回复
  • 我小时候可萌了
    我小时候可萌了
    2023-12-08

    下载的非对称秘钥是txt 文件 -----BEGIN RSA PRIVATE KEY----- 开头的 多了个RAS

    2023-12-08
    赞同
    回复 1
    • Human_nature
      Human_nature
      03-27
      修改,重新下载一下
      03-27
      回复
  • 北枳&橘子
    北枳&橘子
    2023-12-01

    这行 报java.security.NoSuchAlgorithmException: RSASSA-PSS Signature not available 是因为什么

    2023-12-01
    赞同
    回复 3
    • IT全栈工程师-WXN
      IT全栈工程师-WXN
      01-22
      这个问题解决了吗?我也遇到了这个问题,我看有人说是JDK版本的问题,JDK的版本最低需要多少呀
      01-22
      回复
    • 北枳&橘子
      北枳&橘子
      01-25回复IT全栈工程师-WXN
      不是代码的问题 是平台设置的规则没有生效
      01-25
      回复
    • Human_nature
      Human_nature
      03-27回复IT全栈工程师-WXN
      应该是jdk版本不支持这个算法,请使用 BouncyCastleProvider
      03-27
      回复
  • 北枳&橘子
    北枳&橘子
    2023-12-01

    java.security.NoSuchAlgorithmException: RSASSA-PSS Signature not available 说我签名不可用是为啥呀

    2023-12-01
    赞同
    回复 1
    • Human_nature
      Human_nature
      03-27
      应该是jdk版本不支持这个算法,请使用 BouncyCastleProvider
      03-27
      回复

正在加载...

登录 后发表内容