搜索了下论坛关于银联这块的内容,有同学写的 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