Ruby 银联支付 v5.0 版本的接入,有没有相关的例子参考一下.

elele · 2014年12月31日 · 最后由 elele 回复于 2017年12月20日 · 5500 次阅读

搜索了下论坛关于银联这块的内容,有同学写的 gem,但是版本太低了,新版的增加了证书这个东西,找银联技术人员,也没人懂 ruby 这块,暂时也没研究出那个证书是怎么弄进去,来个完整的例子,感激不尽..

亲 你写出来了吗 有一个大概的 demo params = { :version => "5.0.0", :encoding => "utf-8", :certId => "124876885185794726986301355951670452718", :txnType => '01', :txnSubType => "01", :bizType => "000201", :channelType => "08", :frontUrl => "http://localhost:8085/upacp_sdk_php/demo/utf8/FrontReceive.php", :backUrl => "http://114.82.43.123/upacp_sdk_php/demo/utf8/BackReceive.php", :accessType => "0", :merId => "898340183980105", :orderId => '20150409041730', #商户订单号 :txnTime => '20150409041730', #订单发送时间 :txnAmt => '110', :currencyCode => '156', :signMethod => '01', } p = params.sort.map{|key, value| "#{key}=#{value}" }.join('&') data = Digest::SHA1.hexdigest(p) priv_key = "-----BEGIN RSA PRIVATE KEY----***********------END RSA PRIVATE KEY-----" sign = Base64.encode64(OpenSSL::PKey::RSA.new(priv_key).sign('sha1', data.force_encoding("utf-8"))) sign = sign.gsub("\n", "") uri = "https://101.231.204.80:15000/b2c/api/Pay.action" uri = URI.parse(uri) http = Net::HTTP.new uri.host, uri.port http.use_ssl = true if uri.scheme == 'https' http.verify_mode = OpenSSL::SSL::VERIFY_NONE request = Net::HTTP::Post.new uri.request_uri, initheader = {'Content-Type' =>'application/x-www-form-urlencoded'} request = Net::HTTP::Post.new uri.request_uri, initheader = {'Content-Type' =>'application/json'} request.set_form_data(params.merge(signature: sign).sort)

#1 楼 @sun528 thx ,这个问题解决了,有需要的可以参考一下,只是简单的实现

# 银联支付
require 'net/https'
require 'uri'

module OPE
  class Unionpay
    def self.default_options
      #txnType 00 查询交易 01:消费 02:预授权
      # merId 商户Id
      #accessType 0:商户直连接入 1:收单机构接入 2:平台商户接入
      options = {:version => '5.0.0', :txnType => "01", :backUrl => "#{Settings.domain}/notify/unionpay",
                 :merId => Settings.unionpay_store_no, :accessType => "0", :bizType => '000201',
                 :currencyCode => "156", :signMethod => "01", :certId => get_cert_id, :txnSubType => "01",
                 :encoding => "utf-8", :channelType => "07",
                 :frontUrl => "#{Settings.domain}/unionpay/front"}
    end

    def self.create_direct_pay(order,custom_options = {})
      # 测试参数
      options = self.get_options(order)
      options.merge!(custom_options)           rescue nil
      options.symbolize_keys!
      signature = self.sign(options)
      options.merge(:signature => signature)
    end

    def self.query_options(order)
      options = self.get_options(order)
      options.delete(:backUrl)
      options.delete(:frontUrl)
      options.merge!(:txnType => '00', :txnSubType => '00')
      signature = self.sign(options)
      options.merge(:signature => signature)
    end

    def self.get_options(order)
      options ||= {:orderId => order.seq, :txnTime => order.created_at.to_s(:unionpay), :txnAmt => (order.credits * 100).to_i}
      options.merge! self.default_options
    end

    def self.get_cert_id
      get_certificate.certificate.serial.to_i
    end

    def self.get_cret_key
      get_certificate.key
    end

    def self.get_certificate
      OpenSSL::PKCS12.new(File.read(Settings.unionpay_certificate), Settings.unionpay_certificate_psw)
    end

    def self.get_validate_certificate
      OpenSSL::X509::Certificate.new(File.read(Settings.unionpay_validate_certificate))
    end


    def self.sign(param)
      sign_str = self.convert_params(param)
      sha1_sign = Digest::SHA1.hexdigest(sign_str)
      digest = OpenSSL::Digest::SHA1.new
      openssl_sha1 = self.get_cret_key.sign(digest, sha1_sign)
      Base64.encode64(openssl_sha1).gsub(/\s/, '')
    end

    def self.validate(param)
      param.delete('controller')
      param.delete('action')
      signature_str = param.delete('signature')
      signature_str.gsub!(/\s/, '+')
      Rails.logger.info("signature_str    #{signature_str}")
      signature = Base64.decode64(signature_str)
      sign_str = self.convert_params(param)
      sha1_sign = Digest::SHA1.hexdigest(sign_str)
      digest = OpenSSL::Digest::SHA1.new
      self.get_validate_certificate.public_key.verify(digest, signature, sha1_sign)
    end

    def self.convert_params(param)
      sign_str = param.sort.map do |k, v|
        "#{k}=#{v}"
      end.join("&").strip
    end

    def self.app_order(order)
      options = self.create_direct_pay(order)
      page = Mechanize.new { |a| a.ssl_version, a.verify_mode = 'SSLv3', OpenSSL::SSL::VERIFY_NONE }
      doc = page.post(Settings.unionpay_app_front_url, options)
      result = Rack::Utils.parse_query(doc.body)
      if result['respCode'] == '00' && self.validate(result)
        return result
      else
        return false
      end
    end

    #查询订单
    def self.query(order)
      options = query_options(order)
      page = Mechanize.new { |a| a.ssl_version, a.verify_mode = 'SSLv3', OpenSSL::SSL::VERIFY_NONE }
      doc = page.post(Settings.unionpay_query_url, options)
      result = Rack::Utils.parse_query(doc.body)
      order = Order.find_by(:seq => result['orderId'])
      order.trades = result.to_s
      if result['respCode'] == '00' && self.validate(result)
        if result['origRespCode'].blank?
          if order.may_finish?
            order.finish
          end
        end
      end
      order.save!
      result
    end


  end


end

请问:有没有更完整的银联支付的例子?看了 kikyous/unionpay 这位同学的写的 gem. 13 年的,完全没有证书这块的内容。验签等等...

@fodcool 用第三方聚合支付吧。

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