From de4bee90aaa480c4d32dd66048e45cf25329e89f Mon Sep 17 00:00:00 2001 From: varorbc Date: Thu, 16 Nov 2017 15:49:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0APP=E6=94=AF=E4=BB=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/ICanPay.Unionpay/Constant.cs | 1 + src/ICanPay.Unionpay/Merchant.cs | 11 +++- src/ICanPay.Unionpay/Notify.cs | 27 +++++++++ src/ICanPay.Unionpay/Order.cs | 49 +++++++++++++++- src/ICanPay.Unionpay/UnionpayGateway.cs | 77 ++++++++++++++++++++----- src/ICanPay.Unionpay/Util.cs | 13 ----- 6 files changed, 147 insertions(+), 31 deletions(-) diff --git a/src/ICanPay.Unionpay/Constant.cs b/src/ICanPay.Unionpay/Constant.cs index f449eee..130e44f 100644 --- a/src/ICanPay.Unionpay/Constant.cs +++ b/src/ICanPay.Unionpay/Constant.cs @@ -12,5 +12,6 @@ namespace ICanPay.Unionpay public const string QUERYID = "queryId"; public const string RESPCODE = "respCode"; public const string RESPMSG = "respMsg"; + public const string ORDERDESC = "orderDesc"; } } diff --git a/src/ICanPay.Unionpay/Merchant.cs b/src/ICanPay.Unionpay/Merchant.cs index c3eff48..6912c39 100644 --- a/src/ICanPay.Unionpay/Merchant.cs +++ b/src/ICanPay.Unionpay/Merchant.cs @@ -21,6 +21,11 @@ namespace ICanPay.Unionpay /// public string CertId { get; internal set; } + /// + /// 加密证书号 + /// + public string EncryptCertId { get; internal set; } + /// /// 证书私钥 /// @@ -120,12 +125,12 @@ namespace ICanPay.Unionpay ///94:IC卡脚本通知 ///95:查询更新加密公钥证书 /// - public string TxnType { get; internal set; } + public string TxnType { get; internal set; } = "01"; /// /// 交易子类 /// - public string TxnSubType { get; internal set; } + public string TxnSubType { get; internal set; } = "01"; /// /// 产品类型 @@ -140,7 +145,7 @@ namespace ICanPay.Unionpay /// 001001:订购 /// 000202:B2B /// - public string BizType { get; internal set; } + public string BizType { get; internal set; } = "000201"; /// /// 渠道类型 diff --git a/src/ICanPay.Unionpay/Notify.cs b/src/ICanPay.Unionpay/Notify.cs index 600d68f..8ef4a52 100644 --- a/src/ICanPay.Unionpay/Notify.cs +++ b/src/ICanPay.Unionpay/Notify.cs @@ -218,5 +218,32 @@ namespace ICanPay.Unionpay /// 银联受理订单号 /// public string Tn { get; set; } + + /// + /// 支付卡标识 + /// + public string PayCardNo { get; set; } + + /// + /// 支付卡名称 + /// + public string PayCardIssueName { get; set; } + + /// + /// 清算汇率 + /// + public string ExchangeRate { get; set; } + + /// + /// 兑换日期 + /// + public string ExchangeDate { get; set; } + + /// + /// 绑定关系标识号 + /// 适用于代收类绑定产品,字母不区分大小写, + /// 用法:在绑定后支付时客户仅需要上送本字段,无需上送卡号,不支持换行符等不可见字符 用于唯一标识绑定关系 + /// + public string BindId { get; set; } } } diff --git a/src/ICanPay.Unionpay/Order.cs b/src/ICanPay.Unionpay/Order.cs index d8b610d..4e4a15b 100644 --- a/src/ICanPay.Unionpay/Order.cs +++ b/src/ICanPay.Unionpay/Order.cs @@ -27,8 +27,10 @@ namespace ICanPay.Unionpay private double _amount; /// - /// 银联不支持此字段,填写无效 + /// 订单描述,仅APP支付有效 /// + [ReName(Name = Constant.ORDERDESC)] + [StringLength(32, ErrorMessage = "订单描述最大长度为32位")] public string Body { get; set; } /// @@ -57,7 +59,7 @@ namespace ICanPay.Unionpay /// /// 发卡机构代码,当账号类型为 02-存折时需填写 在前台类交易时填写默认银行代码,支持直接跳转到网 银 /// - [StringLength(20, ErrorMessage = "发卡机构代码最大长度为1024位")] + [StringLength(20, ErrorMessage = "发卡机构代码最大长度为20位")] public string IssInsCode { get; set; } /// @@ -65,5 +67,48 @@ namespace ICanPay.Unionpay /// [StringLength(1024, ErrorMessage = "商户自定义保留域最大长度为1024位")] public string ReqReserved { get; set; } + + /// + /// 交易账号。请求时使用加密公钥对交易账号加密,并做 Base64 编码后上送; + /// 应答时如需返回,则使用签名私钥 进行解密。 + /// 前台交易可由银联页面采集,也可由商户上送并返显。 + /// 如需锁定返显卡号,应通过保留域(reserved)上送卡 号锁定标识。 + /// + [StringLength(1024, ErrorMessage = "交易账号最大长度为1024位")] + public string AccNo { get; set; } + + /// + /// 银行卡验证信息及身份信息 + /// 该域需整体做 Base64 编码。 + /// 所有子域需用“有子域包含,子域间以“含,符号链接。 + /// 格式如下:{子域名 1=值&子域名 2=值&子域名 3=值} + /// 各子域取值见注 + /// 1。 借记卡可上送姓名、手机号、证件类型、证件号码; + /// 贷记卡可上送姓名、手机号、证件类型、证件号码、有效 期、CVN2。 + /// 前台交易可以由银联页面采集,无需商户上送,后台交 易必须由商户上送。 + /// 前台交易支持商户上送并返显的要素包含手机号,姓 名,证件号。 + /// + [StringLength(1024, ErrorMessage = "银行卡验证信息及身份信息最大长度为1024位")] + public string CustomerInfo { get; set; } + + /// + /// 分期付款信息域 + /// 相关子域见注 10。 格式如下:{子域名1=值&子域名2=值&子域名3=值} + /// + [StringLength(1024, ErrorMessage = "分期付款信息域最大长度为1024位")] + public string InstalTransInfo { get; set; } + + /// + /// 标记化支付信息域 + /// 格式如下:{子域名1=值&子域名2=值&子域名3=值} + /// 示例: tokenPayData={token=6201002708161330&trId=12345678&tokenLevel=55&tokenBegin=20140816093022&tokenEnd=20150816093021&tokenType=01} + /// + [StringLength(1024, ErrorMessage = "标记化支付信息域最大长度为1024位")] + public string TokenPayData { get; set; } + + /// + /// /持卡人IP + /// + public string CustomerIp { get; set; } } } diff --git a/src/ICanPay.Unionpay/UnionpayGateway.cs b/src/ICanPay.Unionpay/UnionpayGateway.cs index 9a714b9..9631031 100644 --- a/src/ICanPay.Unionpay/UnionpayGateway.cs +++ b/src/ICanPay.Unionpay/UnionpayGateway.cs @@ -11,12 +11,13 @@ namespace ICanPay.Unionpay /// public class UnionpayGateway : GatewayBase, - IFormPayment + IFormPayment, IAppPayment { #region 私有字段 - private const string GATEWAYURL = "https://gateway.test.95516.com/gateway/api/frontTransReq.do"; + private const string FRONTGATEWAYURL = "https://gateway.test.95516.com/gateway/api/frontTransReq.do"; + private const string APPGATEWAYURL = "https://gateway.test.95516.com/gateway/api/appTransReq.do"; private readonly Merchant _merchant; #endregion @@ -39,7 +40,7 @@ namespace ICanPay.Unionpay #region 属性 - public override string GatewayUrl { get; set; } = GATEWAYURL; + public override string GatewayUrl { get; set; } = FRONTGATEWAYURL; public new Merchant Merchant => _merchant; @@ -78,16 +79,59 @@ namespace ICanPay.Unionpay public void InitFormPayment() { - _merchant.TxnType = "01"; - _merchant.TxnSubType = "01"; - _merchant.BizType = "000201"; + InitOrderParameter(); + GatewayUrl = FRONTGATEWAYURL; + } + #endregion + + #region App支付 + + public string BuildAppPayment() + { + InitAppPayment(); + + Commit(); + + return Notify.Tn; + } + + public void InitAppPayment() + { + Util.Sign(_merchant.CertKey, "accessType=0&backUrl=http://222.222.222.222:8080/demo/api_01_gateway/BackRcvResponse.aspx&bizType=000201&certId=68759663125&channelType=08¤cyCode=156&encoding=UTF-8&merId=777290058110048&orderId=20171116133157041&signMethod=01&txnAmt=1000&txnSubType=01&txnTime=20171116133157&txnType=01&version=5.1.0"); + InitOrderParameter(); + GatewayUrl = APPGATEWAYURL; + } + + #endregion + + private void InitOrderParameter() + { GatewayData.Add(Merchant, StringCase.Camel); GatewayData.Add(Order, StringCase.Camel); GatewayData.Add(Constant.SIGNATURE, BuildSign()); } - #endregion + private void Commit() + { + string result = HttpUtil + .PostAsync(GatewayUrl, GatewayData.ToUrl()) + .GetAwaiter() + .GetResult(); + + ReadReturnResult(result); + } + + private void ReadReturnResult(string result) + { + GatewayData.FromUrl(result, false); + base.Notify = GatewayData.ToObject(StringCase.Camel); + if (!IsSuccessPay) + { + throw new GatewayException(Notify.RespMsg); + } + ValidateNotifySign(); + } /// /// 生成签名 @@ -95,7 +139,7 @@ namespace ICanPay.Unionpay /// private string BuildSign() { - return Util.Sign(_merchant.CertKey, GatewayData.ToUrl()); + return Util.Sign(_merchant.CertKey, GatewayData.ToUrl(false)); } /// @@ -104,10 +148,7 @@ namespace ICanPay.Unionpay /// private bool IsSuccessResult() { - if (!ValidateNotifySign()) - { - throw new GatewayException("签名不一致"); - } + ValidateNotifySign(); if (IsSuccessPay) { @@ -122,7 +163,17 @@ namespace ICanPay.Unionpay /// private bool ValidateNotifySign() { - return Util.VerifyData(GatewayData.ToUrl(Constant.SIGNATURE), Notify.Sign, Notify.SignPubKeyCert); + GatewayData.Remove(Constant.SIGNATURE); + + bool result = Util.VerifyData(GatewayData.ToUrl(false), + Notify.Sign, Notify.SignPubKeyCert); + + if (!result) + { + throw new GatewayException("签名不一致"); + } + + return result; } } } diff --git a/src/ICanPay.Unionpay/Util.cs b/src/ICanPay.Unionpay/Util.cs index 6751aa1..a6fc127 100644 --- a/src/ICanPay.Unionpay/Util.cs +++ b/src/ICanPay.Unionpay/Util.cs @@ -179,24 +179,11 @@ namespace ICanPay.Unionpay } string unionpayCnName = "中国银联股份有限公司"; - -#if DEBUG - - // 验证公钥是否属于银联 - if (!unionpayCnName.Equals(cn)) - { - return false; - } - -#else - if (!unionpayCnName.Equals(cn) && !"00040000:SIGN".Equals(cn)) { return false; } -#endif - return true; }