# 微信提现结果通知
- 厂商调用提现微信余额接口后,美团开放平台会回调游戏开发者服务端的回调接口(开发者提供的回调接口的端口号,必须是80或者443),完成提现结果通知。
- 如果游戏开发者服务端返回异常,美团开放平台会进行重试,重试间隔采取递增的策略。
- 回调说明
: 接口回调采取对称加密的方式,假设开发者的回调接口为http://url.callback;则回调时形式如:
method:POST header:application/json;charset=utf-8 url:http://url.callback postdata: { data:加密后的数据, sign:签名 } - 开发者的服务端在接收到回调时,可以使用sign的算法进行签名验证。如果匹配了,说明来自于美团游戏开放平台的接口回调是正确的,开发者可以进一步解密数据包和执行业务逻辑。
##微信提现结果回调开发者接口
通知接口参数:
参数名 类型 默认值 是否必填 说明 sign String 是 签名,签名方法见附录 data String 是 加密后的数据,通知内容(JSON)加密后的生成的字符串,解密方法见附录 data 解密后的内容:
参数名 类型 默认值 是否必填 说明 mgcId String 是 美团游戏平台玩家角色id mgcReqNo String 是 美团侧提现受理号 outReqNo String 是 游戏厂商提现请求传入的申请号 price String 是 美团侧收到的提现金额,单位:分. status String 是 SUCCESS:提现成功,FAIL:提现失败 payChannel String 是 1:提现到微信 开发者服务端接口收到回调通知后,接口响应(code:0代表成功,非0代表失败):
{ "code": 0, "msg": "ok" }
# 附录
- Sign签名的计算算法为
String secretKey = AESUtil.createKey(appId + "&" + appSecret); //开发者可以在开发者后台查询得到开放平台为其分配的appId和appSecret signature = SHAUtil.encryptSHA1Str(data + secretKey) //data :美团开发平台回调返回的报文中data字段对应的value - AESUtil工具类
import java.security.MessageDigest; import javax.crypto.SecretKey; public static String createKey(String password) { try { byte[] key = password.getBytes("UTF-8"); MessageDigest sha = MessageDigest.getInstance("SHA-1"); key = sha.digest(key); key = Arrays.copyOf(key, 32); SecretKey secretKey = new SecretKeySpec(key, "AES"); return Base64.getEncoder().encodeToString(secretKey.getEncoded()); } catch (Exception var3) { throw new RuntimeException(var3); } } - SHAUtil工具类
import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import org.apache.commons.codec.digest.DigestUtils; public static String encryptSHA1Str(String text) { byte[] bytes = encryptSHA(text, "SHA-1"); return byte2hex(bytes); } private static byte[] encryptSHA(String text, String algorithm) { MessageDigest md; try { md = MessageDigest.getInstance(algorithm); } catch (NoSuchAlgorithmException var4) { throw new IllegalArgumentException(var4); } byte[] infoBytes = text.getBytes(StandardCharsets.UTF_8); md.update(infoBytes); return md.digest(); } private static String byte2hex(byte[] bytes) { StringBuilder stringBuilder = new StringBuilder(); byte[] var2 = bytes; int var3 = bytes.length; for(int var4 = 0; var4 < var3; ++var4) { byte b = var2[var4]; String hex = Integer.toHexString(b & 255); if (hex.length() == 1) { stringBuilder.append("0"); } stringBuilder.append(hex); } return stringBuilder.toString(); } - data字段的加密使用AES_256_GCM算法加密,解密工具类如下
- 解密工具类
以下代码为AES_256_GCM的解密java示例代码,仅供参考 import javax.crypto.Cipher; import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Base64; private static final String ALGORITHM = "AES"; private static final String ALGORITHM_PADDING = "AES/GCM/NoPadding"; private static final int GCM_NONCE_LENGTH_BIT = 128; private static final int GCM_TAG_LENGTH_BIT = 128; /** * 解密方法 * @param key 密钥(AESUtil.createKey(appId + "&" + appSecret)) * @param encryptData 密文数据 * @return 明文数据 */ public static String decryptWithAESGCM256(String key, String encryptData) { try { byte[] decodeData = Base64.getUrlDecoder().decode(encryptData); byte[] nonceBytes = Arrays.copyOfRange(decodeData, 0, GCM_NONCE_LENGTH_BIT / 8); byte[] contentBytes = Arrays.copyOfRange(decodeData, GCM_NONCE_LENGTH_BIT / 8, decodeData.length); byte[] keyBytes = Base64.getDecoder().decode(key.getBytes(StandardCharsets.UTF_8)); SecretKeySpec secretKey = new SecretKeySpec(keyBytes, ALGORITHM); GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH_BIT, nonceBytes); Cipher cipher = Cipher.getInstance(ALGORITHM_PADDING, "SunJCE"); cipher.init(Cipher.DECRYPT_MODE, secretKey, spec); return new String(cipher.doFinal(contentBytes), StandardCharsets.UTF_8); } catch (Exception e) { e.printStackTrace(); } return null; }