Ruby 银联手机控件支付相关

sun528 · 2015年04月14日 · 最后由 yunshang 回复于 2016年08月02日 · 2886 次阅读

在现在的公司 做了一个银联的手机控件支付项目,因为银联的 api 不是特别全面,而且不提供 ruby 的代码只能完全按照 php 的代码来进行签名,验签一类的,在转换成 ruby 的代码看看结果能否对上。而发现之前的一些 git 上的相关 gem 包,都不是能用了,而相关信息也很少,所以现在这记录下,然后 gem 地址:https://github.com/Yohansun/unionpay_app 1:介绍下银联的具体流程吧 (1)手机端需要后台返回的 tn 号,利用这个 tn 号和银联进行交易 (2)那么在后台如何和银联交互获得这个 tn 号呢,方法在下面有,首先就是根据 union_params 进行签名#unionpay_sign,然后 post 请求给银联 会返回你类似。 “accessType=0&bizType=000201&certId=21267647932558653966460913033289351200&encoding=utf-8&merId=898111457340146&orderId=20150415122801272&respCode=00&respMsg=\xE6\x88\x90\xE5\x8A\x9F[0000000]&signMethod=01&tn=201504151339264521528&txnSubType=01&txnTime=20150415133926&txnType=01&version=5.0.0&signature=BuCXnTey9ptln9N2rRd5W3ArFkghZB1ayAimmYBqVUktN7KjAROhZw2SFwkdex5NcG71dGEliXi6boUyf13TkcHRIbIfDm+dm5LhUWNpX7DlJgeF+lJxyuFpP2DyogiWtecifSPYbao0tv+t15fyVOp9ioJ5rB5pM+7tX4VT3kIN8mzJl93M46vCXPEaFHLFqTM45B8KRpoZWyBtamckixBftGg+Jg759a+gK5oqRVoen1/AyXNjrUUipKZ+XOLjPKPDrNjtkEOJ1R4VS5JQdyw2WQmn6hoff6aCt/nX1VhLZPzvfTEi8ia9ap6mObDECZ7zkJ2n2N9l24xqi3PrGg==” 这里面就有 tn 值。你把它返回给前端。当然 tn 值过来后 你要进行验签 #unionpay_verify params 这个方法。

#银联的签名 sign
def unionpay_sign txtAmt
    union_params = {
      :version => "5.0.0",
      :encoding => "utf-8",
      :certId => Settings.union.certId, #证书号
      :txnType => '01',
      :txnSubType => "01",
      :bizType => "000201",
      :channelType => "08",
      :frontUrl   => Settings.union.frontUrl,
      :backUrl    => Settings.union.backUrl,
      :accessType => "0",
      :merId      => Settings.union.merId, #商户号
      :orderId => Time.now.strftime("%Y%m%d%H%M%S"),  #商户订单号
      :txnTime => Time.now.strftime("%Y%m%d%H%M%S"),  #订单发送时间
      :txnAmt  => txtAmt, #以分为单位
      :currencyCode => '156',
      :signMethod => '01',
    }
    data = Digest::SHA1.hexdigest(union_params.sort.map{|key, value| "#{key}=#{value}" }.join('&'))
    sign = Base64.encode64(OpenSSL::PKey::RSA.new(Settings.union.private_key).sign('sha1', data.force_encoding("utf-8"))).gsub("\n", "")
    union_params = {trade_number: union_params[:orderId], sign: union_params.merge(signature: sign)} #订单号 和 要发送给 银联的参数信息
  end
 # 调用http的post方法 即可成功发送信息 并通过银联的验签
request = Typhoeus::Request.new(Settings.union.uri, method: :post, params: unionpay_sign(params[:cent].to_i)[:sign], ssl_verifypeer: false, headers: {'Content-Type' =>'application/x-www-form-urlencoded'} )
#银联支付验签
  def unionpay_verify params
    if unionpay_get_public_key_by_cert_id params['certId']
        public_key = unionpay_get_public_key_by_cert_id params['certId']
        signature_str = params['signature']
        p = params.reject{|k, v| k == "signature"}.sort.map{|key, value| "#{key}=#{value}" }.join('&')
        signature = Base64.decode64(signature_str)
        data = Digest::SHA1.hexdigest(p)
        key = OpenSSL::PKey::RSA.new public_key
        digest = OpenSSL::Digest::SHA256.new
        key.verify digest, signature, data
    else
        false
    end
  end

  # 银联支付 根据证书id返回公钥
    def unionpay_get_public_key_by_cert_id cert_id
        certificate = OpenSSL::X509::Certificate.new(Settings.union.cer) #读取cer文件
        certificate.serial.to_s == cert_id ? certificate.public_key.to_s : nil #php 返回的直接是cer文件 Settings.union.cer
    end
#查询接口,查询支付是否成功。
    def unionpay_query order_id
        union_params = {
            :version => '5.0.0',        #版本号
            :encoding => 'utf-8',       #编码方式
            :certId => Settings.union.certId,   #证书ID   
            :signMethod => '01',        #签名方法
            :txnType => '00',       #交易类型   
            :txnSubType => '00',        #交易子类
            :bizType => '000000',       #业务类型
            :accessType => '0',     #接入类型
            :channelType => '07',       #渠道类型
            :orderId => order_id,   #请修改被查询的交易的订单号
            :merId => Settings.union.merId, #商户代码,请修改为自己的商户号
            :txnTime => order_id,   #请修改被查询的交易的订单发送时间
        }
        data = Digest::SHA1.hexdigest(union_params.sort.map{|key, value| "#{key}=#{value}" }.join('&'))
    sign = Base64.encode64(OpenSSL::PKey::RSA.new(Settings.union.private_key).sign('sha1', data.force_encoding("utf-8"))).gsub("\n", "")
    request = Typhoeus::Request.new(Settings.union.uri, method: :post, params: union_params.merge(signature: sign), ssl_verifypeer: false, headers: {'Content-Type' =>'application/x-www-form-urlencoded'} )
    request.run
    if request.response.success?
        code = Hash[*request.response.body.split("&").map{|a| a.gsub("==", "@@").split("=")}.flatten]['origRespCode']
      CentOrder.find_by(trade_number: order_id).update_attributes!(state: 1) if code == "00"
    end
    end

证书 id:cert_id,你是怎样获取到的?

需要 登录 后方可回复, 如果你还没有账号请 注册新账号