同城配送,微信最新出炉的,微信官方对接好多个运力方,价格会稍微低一点,我们只需要充值就可以使用了,但是因为是新出的,文档还是在线文档,而且比较绕,看讨论组里面比较多人也遇到坑,我对接完了就细细盘点一下吧,废话不多说,开搞!
同城配送产品介绍: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 // timestamp与Wechatmp-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());
只想弱弱地问一下,这个api安全打开之后,还能关闭吗?
大佬好,我们也遇到这个问题,想咨询下各位大佬 非对称的密文----BEGIN PRIVATE KEY----开头的私钥怎么查看和下载,只能查看下载-----BEGIN PUBLIC KEY----- 开头的公钥
大佬们,调用成功后AES_Dec 解密时不时验证失败,错误日志: 2023-08-15 09:45:10.248 [http-nio-19109-exec-1] ERROR cn.com.saas.core.utils.AES_Dec - auth tag验证失败 >>> javax.crypto.AEADBadTagException: Tag mismatch! at java.base/com.sun.crypto.provider.GaloisCounterMode$GCMDecrypt.doFinal(GaloisCounterMode.java:1395) at java.base/com.sun.crypto.provider.GaloisCounterMode.engineDoFinal(GaloisCounterMode.java:406) at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2205) at cn.com.saas.core.utils.AES_Dec.getRealResp(AES_Dec.java:54) at cn.com.saas.core.utils.AES_Dec.getResp(AES_Dec.java:106) at cn.com.saas.delivery.service.impl.StoreDeliveryServiceImpl.createStore(StoreDeliveryServiceImpl.java:169) at cn.com.saas.delivery.controller.StoreDeliveryController.createStore(StoreDeliveryController.java:43) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) at javax.servlet.http.HttpServlet.service(HttpServlet.java:665) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) at javax.servlet.http.HttpServlet.service(HttpServlet.java:750) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:96) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.base/java.lang.Thread.run(Thread.java:833)
如果运行第二步RSA_Sign时出现以下错误,可能是因为你的当前jdk版本没有这个 Provider(一个签名算法)
具体解决方法是导入依赖
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.60</version>
</dependency>
并在RSA_Sign中加上
static {
Security.addProvider(new BouncyCastleProvider());
}
详细看装载链接https://blog.csdn.net/piaoranyuji/article/details/126156618
版权声明:本文为CSDN博主「长安明月」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/piaoranyuji/article/details/126156618
微信服务商怎么搞,每一家还得保存他的秘钥吗,不开启也要验证?
服务商用注册邮箱发送申请邮件至 wxwuliu@tencent.com
【邮件标题】 服务商名称 - 同城配送接入申请
【邮件内容】 aes256-gcm密钥、RSA256的公钥、服务商的 component_appid
一直提示签名错误,有办法测试签名是否正确吗。我看PSS每次签名的值都不一样。
膜拜大佬!