微信app支付(V3)

返回上一级

最近项目需要接入微信APP支付,原项目服务器是有相关代码的,不过是V2版本的支付。

服务器请求微信预下单成功后,计算出了签名值发给前端,结果客户端拉起支付提示【支付签名验证失败】。

客户端百度找了各种资料,无奈V2版本的资料太少,现在网上很多是V3的资料,最后决定再接入V3版本。

正文

2022年8月23日19:03:01 已更新增加内置库加解密,不再愚蠢地调用shell和python脚本了….可以拉到最下面)

首先是服务器下单,按照官方文档设置好参数。

请求参数加密

加密方式,官方给出的案例是获取微信支付平台证书。

大致看了一下,当我看到SHA256 with RSA签名的时候心凉了,我们服务器没有这个库,不碍事,直接调用shell命令(事实上后面很多签名都是这样做的)

直接上lua代码

local function syscmd(cmd)
  skynet.error("syscmd. cmd:", cmd)
  local pfile = io.popen(cmd)
  local ret = pfile:read("a")
  pfile:close()
  return ret
end

核心代码

local content = {
    appid = 这里填你的引用ID,       *-- 应用ID*
    mchid = 这里填你的商户ID,     *-- 商户ID*
    description = "游戏道具",   *-- 描述*
    out_trade_no = "服务器自己用的订单号",      *-- 商户系统内部订单号*
    amount = {
      total = "道具价格", *--单位分*
      currency = "CNY",
    },
    notify_url = "回调地址,必须用HTTPS",     *-- 支付成功通知*
  }
local noncestr = random_string_32() *--生成sui 字符串*
local timestamp = tostring(os.time()) *-- 时间戳*
local header_sign_str = string.format([[%s\n%s\n%s\n%s\n%s\n]],
    "POST","/v3/pay/transactions/app",timestamp,noncestr,cjson.encode(content)
  )
*-- 执行shell,apiclient_key.pem这个文件自己到微信商户后台下载*
local header_sign2 = syscmd("echo -n -e  '" .. header_sign_str .. "'  | openssl dgst -sha256 -sign apiclient_key.pem  | openssl base64 -A")
local header = {
   ["Authorization"] = 'WECHATPAY2-SHA256-RSA2048 mchid="' ..
      商户ID .. '",serial_no="这里填商户证书序列号",'
      .. 'nonce_str="' .. noncestr .. '",signature="' .. header_sign2
      .. '",timestamp="' .. timestamp .. '"',
   ["Content-Type"] = "application/json",*--这里必填*
   ["Accept"] = "application/json",*--这里必填*
   ["User-Agent"] = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"*--这里必填*
}
local status, body = httpc.request("POST", "https://api.mch.weixin.qq.com", '/v3/pay/transactions/app', nil, header, cjson.encode(content))
print("=====================",status,body)

(”User-Agent”字段随便百度填的。。如果不填,回调会提示缺少”Accept” 或”User-Agent”)

不出意外,这应该就下单成功了,成功后会获得一个prepay_id,再次加密拿给客户端拉起支付,代码如下

local info = cjson.decode(body)
info.out_trade_no = orderNo
if info.prepay_id and info.prepay_id~="" then
  local order = {
    appid = game.wx_appid,
    mchid = game.wx_mch_id,
    noncestr = noncestr,   
    timestamp = timestamp, *-- 时间戳*
    prepayid = info.prepay_id
  }
  local client_sign_str = string.format('%s\n%s\n%s\n%s\n',order.appid,order.timestamp,order.noncestr,info.prepay_id)
  order.sign = syscmd("echo -n -e  '" .. client_sign_str .. "'  | openssl dgst -sha256 -sign apiclient_key.pem  | openssl base64 -A")
  local t = {
    out_trade_no = orderNo,
    orderStr = cjson.encode(order),
    plat = arg.platform,
  }
  return t
else
  info.err = "request wx failed"
  return info
end

微信回调

官方文档在这里

收到的是json,判断一下body中event_type字段是否为”TRANSACTION.SUCCESS”,否则为支付失败

这里解密用的签名是我调用的python脚本…(官方解密)

local function get_sign(header,body)
  local info  = cjson.decode(body).resource
  *-- util.print_r(info)*
  local V3_key = "这里填自己商户V3key"
  local ret = syscmd("python aead_aes_256_gcm.py recharge " .. V3_key .. " " .. (info.nonce or "") .. " " .. (info.ciphertext or "") .. " " .. (info.associated_data or ""))
  print("执行结果:")
  skynet.error("执行结果:",ret)
  if not ret or ret == "" then
    skynet.error("订单解密失败")
    return false
  end
  local real_order = cjson.decode(ret)
  return true,real_order
end

这里解密后得到充值数据,通知游戏服充值成功。

aead_aes_256_gcm.py文件如下

# -*- coding: UTF-8 -*-`

from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import base64
import subprocess
import sys,io

def decrypt(tp,key,nonce, ciphertext, associated_data):

  key_bytes = str.encode(key)
  nonce_bytes = str.encode(nonce)
  ad_bytes = str.encode(associated_data)
  data = base64.b64decode(ciphertext)

  aesgcm = AESGCM(key_bytes)
  print(aesgcm.decrypt(nonce_bytes, data, ad_bytes))`

if __name__ == '__main__':
  decrypt(sys.argv[1],sys.argv[2],sys.argv[3],sys.argv[4],sys.argv[5])

PS:

也许应该先对回调进行签名验证后再做下一步操作?有点麻烦,直接解密算球,有人伪造就认了吧…

2022年8月23日19:03:45更新

使用内置C库加解密

这几天思前想后,用shell和python脚本来加解密代码实在丑陋,就找了各种大佬咨询加密库,最终还是找到了。

服务器下单

修改为

local header_sign2 = cfadmin_crypt_rsa.rsa_sign(header_sign_str,wechat_pay_v3_apiclient_pem_data,"sha256")

给客户的加密

order.sign = cfadmin_crypt_rsa.rsa_sign(client_sign_str,wechat_pay_v3_apiclient_pem_data,"sha256")

支付回调解密

local c_ret = cfadmin_crypt_aes.aes_256_gcm_decrypt(V3_key,crypt.base64decode(info.ciphertext),info.nonce,(info.associated_data or ""))
© 江山山 all right reserved,powered by Gitbook最后更新时间: 2024-08-12 10:00:01

results matching ""

    No results matching ""