支付宝App支付的thinkjs服务端实现

5 篇文章 0 订阅
4 篇文章 0 订阅

阿里的文档非常恼火,一路的坑,最后总算弄出来了。

直接上代码。。。


const fs     = require('fs');
const crypto = require('crypto');
const Base   = require('./base.js');

const AlipaySdk      = require('alipay-sdk').default;
const AlipayFormData = require('alipay-sdk/lib/form').default;

const app_pri_key = fs.readFileSync('./path/app-pri-key.txt', 'ascii');
const ali_pub_key = fs.readFileSync('./path/ali-pub-key.txt', 'ascii');

const alipaySdk = new AlipaySdk(
  {
    appId           : think.config('alipay').appid,
    privateKey      : app_pri_key,
    alipayPublicKey : ali_pub_key,
    sign_type       : 'RSA2',
    charset         : 'utf-8',
  }
);


module.exports = class extends Base {


  verify(param) {

    let map  = [];
    let keys = Object.keys( param );  // 获取所有的key
    keys.sort();                      // 排序

    for( let key of keys )
    {
        //剔除空值及签名字段
        if( key != 'sign' && key != 'sign_type' &&  param[key] ) 
        {
          map.push(`${key}=${param[key]}`);
        }
    }

    let content = map.join('&');

    // 准备公钥的格式
    let publickey = ['-----BEGIN PUBLIC KEY-----\n'];
    let i = 0;
    while( i < ali_pub_key.length )
    {
        publickey.push( ali_pub_key.substring(i, i + 64) + '\n' );
        i += 64;
    }
    publickey.push('-----END PUBLIC KEY-----');
    
    let verify;
    if( param["sign_type"].toUpperCase() === 'RSA2' ) {
      verify = crypto.createVerify( "RSA-SHA256" );
    } 
    else 
    if( param["sign_type"].toUpperCase() === 'RSA'  ) {
      verify = crypto.createVerify( "RSA-SHA1" );
    }

    if( think.isEmpty(verify) ) {
      return false;
    }

    verify.update( content );
    let retval = verify.verify( publickey.join(''), param["sign"], 'base64' );
    return retval;
  }


  async submit_orderAction() {

    let account         = this.get('account');      // 账号
    let item_name       = this.get('item_name');    // 商品识别码(gamme server和网站必须相同)
    let count           = this.get('count');
    let comment         = this.get('comment');

    if( think.isEmpty(account)   ||
        think.isEmpty(item_name) || 
        think.isEmpty(count) )
    {
        return this.fail( 6000, "invalid argument" );
    }

    if( think.isEmpty(comment) ) {
        comment = '';
    }

    // 查询得到商品的数据=
    let item = await this.model('', 'mysql').find_item( item_name );

    if( think.isEmpty(item) ) {
        return this.fail( 6001, "invalid item" );
    }

    // 填充商品数据
    let detail          = item.name + " * " + count;                       // 比如xxx * 3
    let sale_off        = item.sale_off;
    let original_price  = item.price * count;
    let actual_price    = original_price * sale_off;

    // 创建订单并插入到数据库中
    let order_id = await this.model('', 'mysql').save(
      account, item_name, detail, count, original_price, actual_price, sale_off, comment );

    if( think.isEmpty(order_id) ) {
        return this.fail( 6002, "create order failed" );
    }

    // 调用alipay,生成交易号
    let formData = new AlipayFormData();
    let notify   = think.config('alipay').notify;

    formData.setMethod ('get');
    formData.addField  ('notifyUrl', notify );
    formData.addField  ('bizContent', 
      {
        outTradeNo  : order_id.toString(),              // 商户订单号,64个字符以内、可包含字母、数字、下划线,且不能重复
        ProductCode : 'QUICK_MSECURITY_PAY',
        totalAmount : (actual_price / 100).toString(),  // 订单总金额,单位为元,精确到小数点后两位
        subject     : item.stencil,                     // 订单标题
        body        : item.name,                        // 订单描述
      }
    );
      
    // result 为可以跳转到支付链接的 url
    const result = await alipaySdk.exec(  
      'alipay.trade.app.pay',                  // 统一收单下单并支付接口
      {},                                      // api 请求的参数(包含“公共请求参数”和“业务参数”)
      { formData: formData },
    );

    // 返回的url去除支付宝网关获取到orderString,可以直接给客户端请求。
    return this.json( 
      {
        order_id        : order_id,
        sale_off        : sale_off,
        original_price  : original_price,
        actual_price    : actual_price,
        detail          : detail,
        result          : result.replace('https://openapi.alipay.com/gateway.do?',''),
      }
    );
  }


  async notifyAction() {

    // should install think-payload first.
    // detail: https://github.com/thinkjs/think-payload

    let info = this.ctx.request.body;
    if( think.isEmpty(info) ) {
        return this.fail( 6000, 'invalid arguments');
    }

    let params = info.post;    
    if( params['trade_status'] != "TRADE_SUCCESS" ) 
    {
      return this.fail( 6010, 'payment failed.' );
    }

    // 检查参数是否合法
    if( this.verify(params) == false )
    {
      return this.fail( 6003, "failed" );
    }

    let item       = params['subject'];
    let order_id   = params['out_trade_no'];
    let payment_sn = params['trade_no'];
    let money      = params['receipt_amount'];

    // 更新订单(仅更新一个标志,反复读写不会有任何障碍)
    let retval = await this.model('', 'mysql').
      update_payment(order_id, payment_sn, item, parseInt(money * 100) );

    if( retval == 1 ) {
        return this.success( "success" );
    }
    
    // 错误的单号或则金额
    return this.fail( 6012, "failed" );
  }
  
  

}

最后说一句,那个密钥格式别弄错了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值