收藏
回答

小程序即时配送加密签名40234?为什么/(ㄒoㄒ)/~~,官方大大

// 云函数入口文件
const cloud = require('wx-server-sdk')
const request = require('request'); // 引入 request 库
const crypto = require('crypto');
cloud.init({
  env: cloud.DYNAMIC_CURRENT_ENV
}) // 使用当前云环境


// 云函数入口函数
exports.main = async (event, context) => {
  const wxContext = cloud.getWXContext()
  try {
    // 获取access_token和请求参
    const {
      access_token,
      queryParams
    } = event


    // 获取加密请求数据
    const ctxEco = getEcoCtx('https://api.weixin.qq.com/cgi-bin/express/intracity/querystore'// 开发者本地信息
    console.log("ctxEco", ctxEco)
    const req = queryParams // 请求数据
    console.log("req", req)
    const newReq = getNewReq(ctxEco, req) // 生成加密请求数据
    console.log("newReq", newReq)
    const ctxSign = getSignCtx('https://api.weixin.qq.com/cgi-bin/express/intracity/querystore')
    console.log("ctxSign", ctxSign)
    const signature = getSignature(ctxSign, newReq) // 获取签名
    console.log("signature", signature)
    // 执行查询门店接口请求
    const response = await queryStore(access_token, signature, newReq)
    console.log("response", response)
    return response;
  } catch (error) {
    console.error('请求错误:', error);
    return error;
  }
}


// 查询门店信息的POST请求
async function queryStore(access_token, signature, newReq{
  const url = `https://api.weixin.qq.com/cgi-bin/express/intracity/querystore?access_token=${access_token}`;


  const rp = options =>
    new Promise((resolve, reject) => {
      request(options, (error, response, body) => {
        if (error) {
          reject(error);
        }
        resolve(response);
      });
    });
  const result = await rp({
    url: url,
    method'POST',
    jsontrue// 自动将请求体转换为JSON格式
    headers: {
      'Wechatmp-Appid''appid',
      'Wechatmp-TimeStamp': newReq.req_ts,
      'Wechatmp-Signature': signature
    },
    body: newReq // 将加密数据作为请求体
  });
  return result.body;
}


// 获取开发者本地信息
function getSignCtx(url{
  let ctx = {
    local_private_key"-----BEGIN RSA PRIVATE KEY-----\n-----END RSA PRIVATE KEY-----",
    local_sn"sn",
    local_appid"appid",
    url_path: url
  }
  return ctx
}


// 仅做演示,敏感信息请勿硬编码
function getEcoCtx(url{
  let ctx = {
    local_sym_key"sym_key",
    local_sym_sn"sym_sn",
    local_appid"appid",
    url_path: url
  }
  return ctx
}


// 获取加密后的请求数据
function getNewReq(ctx, req{
  const { local_sym_key, local_sym_sn, local_appid, url_path } = ctx // 开发者本地信息
  const local_ts = Math.floor(Date.now() / 1000//加密签名使用的统一时间戳
  const nonce = crypto.randomBytes(16).toString('base64').replace(/=/g'')


  const reqex = {
    _n: nonce,
    _appid: local_appid,
    _timestamp: local_ts
  }


  const real_req = Object.assign({}, reqex, req) // 生成并添加安全校验字段
  const plaintext = JSON.stringify(real_req)


  const aad = `${url_path}|${local_appid}|${local_ts}|${local_sym_sn}`


  const real_key = Buffer.from(local_sym_key, "base64")
  const real_iv = crypto.randomBytes(12)
  const real_aad = Buffer.from(aad, "utf-8")
  const real_plaintext = Buffer.from(plaintext, "utf-8")


  const cipher = crypto.createCipheriv("aes-256-gcm", real_key, real_iv)
  cipher.setAAD(real_aad)


  let cipher_update = cipher.update(real_plaintext)
  let cipher_final = cipher.final()
  const real_ciphertext = Buffer.concat([cipher_update, cipher_final])
  const real_authTag = cipher.getAuthTag()


  const iv = real_iv.toString("base64")
  const data = real_ciphertext.toString("base64")
  const authtag = real_authTag.toString("base64")


  const req_data = {
    iv,
    data,
    authtag,
  }


  const new_req = {
    req_ts: local_ts,
    req_dataJSON.stringify(req_data)
  }
  return new_req
}


// 获取签名
function getSignature(ctx, req{
  const { local_private_key, local_sn, local_appid, url_path } = ctx // 开发者本地信息
  const { req_ts, req_data } = req // 待请求API数据


  const payload = `${url_path}\n${local_appid}\n${req_ts}\n${req_data}`
  const data_buffer = Buffer.from(payload, 'utf-8')
  const key_obj = {
    key: local_private_key,
    padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
    saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST // salt长度,需与SHA256结果长度(32)一致
  }


  const sig_buffer = ss_buffer = crypto.sign(
    'RSA-SHA256',
    data_buffer,
    key_obj
  )
  const sig = sig_buffer.toString('base64')
  return sig
}
回答关注问题邀请回答
收藏

1 个回答

  • 给我爱吃的
    给我爱吃的
    11-18
      const result = await rp({
        url: url,
        method: 'POST',
        // json: true, // 自动将请求体转换为JSON格式
        headers: {
          'Content-type''application/json;charset=utf-8',
          'Wechatmp-Appid''wx5c396ba640e68749',
          'Wechatmp-TimeStamp': newReq.req_ts,
          'Wechatmp-Signature': signature
        },
        body: newReq.req_data // 将加密数据作为请求体
      });
      return result.body;
    


    以上是我在云函数中使用引入request库发起的请求,对于加密和签名后的api请求要把json:true去除

    还有一个问题

    const new_req = {
            req_ts: local_ts,
            req_data: JSON.stringify(req_data)
        }
        return new_req
    


    官方代码中加密后return的new_req是带时间戳的,方便签名方法直接传参使用,我们具体发送请求的时候一定要用new_req.req_data,

    当上述 两个问题加在一起时 会导致 40234 , invalid signature

    如果你的签名和加密参数没问题不妨看下有没有像我一样粗心 😊

    11-18
    有用 1
    回复
登录 后发表内容