Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加了小程序同城配送接口和WxMaService增加了API签名支持 #3404

Merged
merged 4 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added images/api-signature/api-signature-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/api-signature/api-signature-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 46 additions & 0 deletions weixin-java-miniapp/api-signature-readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# 使用API签名

如果对API签名不了解,可先阅读微信文档 [服务端API签名指南](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/getting_started/api_signature.html)

有API数据加密与签名两种功能,此处按照微信文档,简称为签名。

## 程序内设置

[WxMaConfig](src/main/java/cn/binarywang/wx/miniapp/config/WxMaConfig.java)类增加了几个属性,分别对应小程序内设置的签名密钥等。

* apiSignatureAesKey
* apiSignatureAesKeySn
* apiSignatureRsaPrivateKey
* apiSignatureRsaPrivateKeySn

这4个属性需要按照小程序后台设置。

## 小程序后台设置/查看签名用密钥

在小程序后台,开发管理 -> 开发设置 -> API安全处,可以看到如下图界面。

![图一](../images/api-signature/api-signature-1.png)

上图中A处对应 apiSignatureAesKeySn; B处对应apiSignatureAesKey; C处对应apiSignatureRsaPrivateKeySn

apiSignatureRsaPrivateKey 在上图中**无**对应,C处右侧是公钥,apiSignatureRsaPrivateKey 需要的是私钥。

可点击图上右上角的修改,打开如下图的设置页面

![图二](../images/api-signature/api-signature-2.png)

首先确保对称密钥选中 AES256,非对称密钥选中RSA。不要选SM4和SM2。
(如果需要支持SM4/SM2,可修改BaseWxMaServiceImpl.java中postWithSignature方法中相应部分实现)。

在API非对称密钥中下方左侧有个「随机生成密钥对」,点击它,然后点它右侧的「下载私钥」,之后点击「确认」保存。
下载得到的文件是PKCS1格式的私钥,用openssl可转成PKCS8格式。apiSignatureRsaPrivateKey 需要设置的是PKCS8格式的私钥。

注意:

1. 如果不先点击「随机生成密钥对」,直接点击「下载私钥」得到的是公钥,公钥在这里没有用途。
2. 打开下载的文件,第一行是「-----BEGIN RSA PRIVATE KEY-----」说明是PKCS1格式私钥。
3. PKCS8格式第一行是「-----BEGIN PRIVATE KEY-----」
4. 转换命令 `openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in PKCS1格式密钥文件名 -out 新的PKCS8格式密钥文件名`
5. 如果密钥文件有 PUBLIC KEY 字样,说明下载了公钥,重新生成密钥对,下载私钥


Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package cn.binarywang.wx.miniapp.api;

import cn.binarywang.wx.miniapp.bean.intractiy.*;
import java.util.List;
import me.chanjar.weixin.common.error.WxErrorException;

/**
* 微信小程序 物流服务 同城配送服务API <br>
* *不是*即时配送接口,两个相近,容易混淆<br>
* 微信相关接口 <br>
* https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/intracity_service.html
*/
public interface WxMaIntracityService {

/** 申请开通门店权限 */
void apply() throws WxErrorException;

/** 创建门店 */
String createStore(WxMaStore store) throws WxErrorException;

/**
* 更新门店;只更新store中不为null的部分 wxStoreId和outStoreId至少要有一个不为null,根据这2个来更新。 仅支持更新 storeName orderPattern
* serviceTransPrefer addressInfo几个属性
*/
void updateStore(WxMaStore store) throws WxErrorException;

/** 查询门店(列出所有门店) */
List<WxMaStore> listAllStores() throws WxErrorException;

/** 根据wx_store_id查询门店 */
WxMaStore queryStoreByWxStoreId(String wxStoreId) throws WxErrorException;

/** 根据 out_store_id 查询门店 */
List<WxMaStore> queryStoreByOutStoreId(String outStoreId) throws WxErrorException;

/** 门店运费充值,返回充值URL */
String storeCharge(WxMaStoreChargeRequest request) throws WxErrorException;

/** 门店运费退款,返回退款金额 */
int storeRefund(WxMaStoreRefundRequest request) throws WxErrorException;

/** 门店运费流水查询 */
WxMaStoreFlowResponse<? extends WxMaStoreFlowResponse.BasicFlowRecord> queryFlow(
WxMaQueryFlowRequest request) throws WxErrorException;

/** 查询门店余额 */
WxMaStoreBalance balanceQuery(String wxStoreId, String serviceTransId, PayMode payMode)
throws WxErrorException;

/**
* 设置扣费主体 <br>
* 接口调用成功后,小程序的管理员会收到模板消息,点击模板消息确认更改门店扣费主体后,修改生效。
*/
void setPayMode(PayMode payMode) throws WxErrorException;

/** 查询扣费主体 */
WxMaGetPayModeResponse getPayMode() throws WxErrorException;

/** 查询运费 */
WxMaAddOrderResponse preAddOrder(WxMaPreAddOrderRequest request) throws WxErrorException;

/** 创建配送单 */
WxMaAddOrderResponse addOrder(WxMaAddOrderRequest order) throws WxErrorException;

/** 查询配送单 根据wxOrderId */
WxMaOrder queryOrderByWxOrderId(String wxOrderId) throws WxErrorException;

/** 依据商户订单号 查询配送单 */
WxMaOrder queryOrderByStoreOrderId(String wxStoreId, String storeOrderId) throws WxErrorException;

/** 依据微信订单号 查询配送单 */
WxMaCancelOrderResponse cancelOrderByWxOrderId(
String wxOrderId, int cancelReasonId, String cancelReason) throws WxErrorException;

/** 依据商户订单号 查询配送单 */
WxMaCancelOrderResponse cancelOrderByStoreOrderId(
String wxStoreId, String storeOrderId, int cancelReasonId, String cancelReason)
throws WxErrorException;

/**
* 查询支持同城配送的城市
*
* @param serviceTransId 运力ID,传NULL则返回所有
*/
List<WxMaTransCity> getCity(String serviceTransId) throws WxErrorException;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package cn.binarywang.wx.miniapp.api;

import cn.binarywang.wx.miniapp.bean.WxMaApiResponse;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.binarywang.wx.miniapp.executor.ApiSignaturePostRequestExecutor;
import com.google.gson.JsonObject;
import java.util.Map;
import java.util.function.Function;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.service.WxImgProcService;
Expand All @@ -11,33 +15,25 @@
import me.chanjar.weixin.common.util.http.RequestExecutor;
import me.chanjar.weixin.common.util.http.RequestHttp;

import java.util.Map;

/**
* The interface Wx ma service.
*
* @author <a href="https://github.com/binarywang">Binary Wang</a>
*/
public interface WxMaService extends WxService {
/**
* 获取access_token.
*/
String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
String GET_STABLE_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/stable_token";
/** 获取access_token. */
String GET_ACCESS_TOKEN_URL =
"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";

String GET_STABLE_ACCESS_TOKEN = "https://api.weixin.qq.com/cgi-bin/stable_token";

/**
* The constant JSCODE_TO_SESSION_URL.
*/
/** The constant JSCODE_TO_SESSION_URL. */
String JSCODE_TO_SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";
/**
* getPaidUnionId
*/

/** getPaidUnionId */
String GET_PAID_UNION_ID_URL = "https://api.weixin.qq.com/wxa/getpaidunionid";

/**
* 导入抽样数据
*/
/** 导入抽样数据 */
String SET_DYNAMIC_DATA_URL = "https://api.weixin.qq.com/wxa/setdynamicdata";

/**
Expand All @@ -51,28 +47,31 @@ public interface WxMaService extends WxService {

/**
* 导入抽样数据
*
* <pre>
* 第三方通过调用微信API,将数据写入到setdynamicdata这个API。每个Post数据包不超过5K,若数据过多可开多进(线)程并发导入数据(例如:数据量为十万量级可以开50个线程并行导数据)。
* 文档地址:https://wsad.weixin.qq.com/wsad/zh_CN/htmledition/widget-docs-v3/html/custom/quickstart/implement/import/index.html
* http请求方式:POST http(s)://api.weixin.qq.com/wxa/setdynamicdata?access_token=ACCESS_TOKEN
* </pre>
*
* @param lifespan 数据有效时间,秒为单位,一般为86400,一天一次导入的频率
* @param type 用于标识数据所属的服务类目
* @param scene 1代表用于搜索的数据
* @param data 推送到微信后台的数据列表,该数据被微信用于流量分配,注意该字段为string类型而不是object
* @param type 用于标识数据所属的服务类目
* @param scene 1代表用于搜索的数据
* @param data 推送到微信后台的数据列表,该数据被微信用于流量分配,注意该字段为string类型而不是object
* @throws WxErrorException .
*/
void setDynamicData(int lifespan, String type, int scene, String data) throws WxErrorException;

/**
*
*
* <pre>
* 验证消息的确来自微信服务器.
* 详情请见: http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421135319&token=&lang=zh_CN
* </pre>
*
* @param timestamp the timestamp
* @param nonce the nonce
* @param nonce the nonce
* @param signature the signature
* @return the boolean
*/
Expand All @@ -88,6 +87,8 @@ public interface WxMaService extends WxService {
String getAccessToken() throws WxErrorException;

/**
*
*
* <pre>
* 获取access_token,本方法线程安全.
* 且在多线程同时刷新时只刷新一次,避免超出2000次/日的调用次数上限
Expand All @@ -106,6 +107,8 @@ public interface WxMaService extends WxService {
String getAccessToken(boolean forceRefresh) throws WxErrorException;

/**
*
*
* <pre>
* 用户支付完成后,获取该用户的 UnionId,无需用户授权。本接口支持第三方平台代理查询。
*
Expand All @@ -114,33 +117,45 @@ public interface WxMaService extends WxService {
* 文档地址:https://developers.weixin.qq.com/miniprogram/dev/api/getPaidUnionId.html
* </pre>
*
* @param openid 必填 支付用户唯一标识
* @param openid 必填 支付用户唯一标识
* @param transactionId 非必填 微信支付订单号
* @param mchId 非必填 微信支付分配的商户号,和商户订单号配合使用
* @param outTradeNo 非必填 微信支付商户订单号,和商户号配合使用
* @param mchId 非必填 微信支付分配的商户号,和商户订单号配合使用
* @param outTradeNo 非必填 微信支付商户订单号,和商户号配合使用
* @return UnionId. paid union id
* @throws WxErrorException .
*/
String getPaidUnionId(String openid, String transactionId, String mchId, String outTradeNo) throws WxErrorException;
String getPaidUnionId(String openid, String transactionId, String mchId, String outTradeNo)
throws WxErrorException;

/**
*
*
* <pre>
* Service没有实现某个API的时候,可以用这个,
* 比{@link #get}和{@link #post}方法更灵活,可以自己构造RequestExecutor用来处理不同的参数和不同的返回类型。
* 可以参考,{@link MediaUploadRequestExecutor}的实现方法
* </pre>
*
* @param <T> .
* @param <E> .
* @param <T> .
* @param <E> .
* @param executor 执行器
* @param uri 接口请求地址
* @param data 参数或请求数据
* @param uri 接口请求地址
* @param data 参数或请求数据
* @return . t
* @throws WxErrorException the wx error exception
*/
<T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException;

WxMaApiResponse execute(
ApiSignaturePostRequestExecutor executor,
String uri,
Map<String, String> headers,
String data)
throws WxErrorException;

/**
*
*
* <pre>
* 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试.
* 默认:1000ms
Expand All @@ -151,6 +166,8 @@ public interface WxMaService extends WxService {
void setRetrySleepMillis(int retrySleepMillis);

/**
*
*
* <pre>
* 设置当微信系统响应系统繁忙时,最大重试次数.
* 默认:5次
Expand All @@ -177,7 +194,7 @@ public interface WxMaService extends WxService {
/**
* Map里 加入新的 {@link WxMaConfig},适用于动态添加新的微信公众号配置.
*
* @param miniappId 小程序标识
* @param miniappId 小程序标识
* @param configStorage 新的微信配置
*/
void addConfig(String miniappId, WxMaConfig configStorage);
Expand All @@ -190,8 +207,8 @@ public interface WxMaService extends WxService {
void removeConfig(String miniappId);

/**
* 注入多个 {@link WxMaConfig} 的实现. 并为每个 {@link WxMaConfig} 赋予不同的 {@link String mpId} 值
* 随机采用一个{@link String mpId}进行Http初始化操作
* 注入多个 {@link WxMaConfig} 的实现. 并为每个 {@link WxMaConfig} 赋予不同的 {@link String mpId} 值 随机采用一个{@link
* String mpId}进行Http初始化操作
*
* @param configs WxMaConfig map
*/
Expand All @@ -200,7 +217,7 @@ public interface WxMaService extends WxService {
/**
* 注入多个 {@link WxMaConfig} 的实现. 并为每个 {@link WxMaConfig} 赋予不同的 {@link String label} 值
*
* @param configs WxMaConfig map
* @param configs WxMaConfig map
* @param defaultMiniappId 设置一个{@link WxMaConfig} 所对应的{@link String defaultMiniappId}进行Http初始化
*/
void setMultiConfigs(Map<String, WxMaConfig> configs, String defaultMiniappId);
Expand Down Expand Up @@ -328,9 +345,7 @@ public interface WxMaService extends WxService {
*/
WxMaPluginService getPluginService();

/**
* 初始化http请求对象.
*/
/** 初始化http请求对象. */
void initHttp();

/**
Expand Down Expand Up @@ -403,15 +418,13 @@ public interface WxMaService extends WxService {
*/
WxMaShopAfterSaleService getShopAfterSaleService();


/**
* 返回小程序交易组件-物流服务接口
*
* @return
*/
WxMaShopDeliveryService getShopDeliveryService();


/**
* 返回小程序交易组件-订单服务接口
*
Expand Down Expand Up @@ -544,18 +557,21 @@ public interface WxMaService extends WxService {
* @return getWxMaOpenApiService
*/
WxMaOpenApiService getWxMaOpenApiService();

/**
* 小程序短剧管理
*
* @return getWxMaVodService
*/
WxMaVodService getWxMaVodService();

/**
* 小程序虚拟支付
*
* @return getWxMaXPayService
*/
WxMaXPayService getWxMaXPayService();

WxMaExpressDeliveryReturnService getWxMaExpressDeliveryReturnService();

/**
Expand All @@ -564,4 +580,14 @@ public interface WxMaService extends WxService {
* @return WxMaPromotionService
*/
WxMaPromotionService getWxMaPromotionService();

String postWithSignature(String url, Object obj) throws WxErrorException;

String postWithSignature(String url, JsonObject jsonObject) throws WxErrorException;

/**
* 微信物流服务 -- 同城配送
* https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/industry/express/business/intracity_service.html
*/
WxMaIntracityService getIntracityService();
}
Loading