代码改变世界

支付宝及时到帐接口使用详解深入版

2010-07-21 17:07  苏飞  阅读(6014)  评论(3编辑  收藏  举报

    阅读并下载例子:http://www.cckan.net/forum.php?mod=viewthread&tid=191

自上一次写的 支付宝及时到帐接口使用详解 有几个月了,上次的例子比较简单,适合大家学习使用,本次文章我将分两次和大家一起分享一下我在开发支付接口和国内众多银行接口和第三方的支付平台接口等方面的经验。

    短短两年的时间,我公司也写过不少接口方面的东东了,在这里和大家分享我的心得和体会,一般人一说到和什么接口对接可能会感觉 到很难,或是感觉很利害的样子,如果是和银行的接口对接,那首先想到的就是安全问题,再就是技术含量,其实不然,接口的产生是为了方便双方的合作,基本没有听说过有那两家公司因为程序对接 不上而放弃合作的,基本没有,都是其它方面的原因,接口是为了方便对接和不同公司和程序之间的交互和通信的,都是为了方便,不是我们想像的那样难,高技术含量,要说技术含量吧也是有一些

    我根据自己的开发心得总结一下吧


          这种方式的做法是,服务方提供一个方法,但是一般会在第一个参数或是最后一个参数验证一下加密串,这个加密串一般是用所传的参数组合加密而来,最常见的就是MD5加密了,像支付宝的就是。我把这一类型的看做是最低级的一种,因为这种是最不安全的,只要我知道了你的加密算法和后就可以自己改动参数了

     对于Http的方法最重要的只有一个方法

代码
  /// <summary>
    
/// 请求指定 URL 资源,并获取响应结果
    
/// </summary>
    
/// <param name="url">需要请求的 URL 资源</param>
    
/// <returns>
    
/// 响应结果;
    
/// 出现任意异常,均返回字串"Runtime Error"
    
/// </returns>
    private string RequestContent(string url)
    {
        
string content = string.Empty;
        
try
        {
            HttpWebRequest request 
= (HttpWebRequest)WebRequest.Create(url);
            request.KeepAlive 
= false;
            HttpWebResponse response 
= (HttpWebResponse)request.GetResponse();
            StreamReader reader 
= new StreamReader(response.GetResponseStream(), Encoding.Default);
            content 
= reader.ReadToEnd();
            reader.Close();
        }
        
catch (Exception)
        {
            content 
= "Runtime Error";
        }
        
return content;
    }

 

    只要我们把要传的参数和URL对接后传给这 个方法就算是完事了,另外在MD5加密是时间注意对方是否要区分大小写,最好是把加密串一下子全转成小写或是大写的 

加密的方法一般如下

 

代码
 /// <summary>
    
/// 传入明文,返回用MD%加密后的字符串
    
/// </summary>
    
/// <param name="str">要加密的字符串</param>
    
/// <returns>用MD5加密后的字符串</returns>
    public static string ToMD5(string str)
    {
        
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(str, "md5");
    }

 

 

         在做这样的接口的时候一定要注意一定要验证的地方有三点:

   第一点就是验证加密串了

          这里就是把所需要的参数在本地加一下密然后和服务端发来的对比

    第二点就是控制页面只在首次加载时执行这个我们可以通过下面的方式来实现


        
if (!IsPostBack)
        {
            ............
        }

 

我们只要在IF块里面写我们的代码就可以了

    第三点也是最关键的一点那就是验证一下请求过来的DNS或是IP

     就是说你要验证一下发过来请求的来源电脑是不是你的服务商的DNS或是IP,如果不是就可以不执行程序或是提示为非法操作,这样可以防止有人知道了你的加密算法后自己生成一些代码来高乱你的程序给公司带来损失,特别是即使到账的接口,这一点一定要验证好,而且在IIS服务器最好是绑定一下IP,只接收授权的IP发来的消息。这样基本可以保证安全问题了。

  好了对于 这种方法我来用一个Http的例子来演示一下吧

代码
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Collections.Specialized;
using System.IO;
using Gateway;
using SystemModel;

/// <summary>
/// 创建该页面文件时,请留心该页面文件是可以对其进行美工处理的,原因在于支付完成以后,当前窗口会从支付宝的页面跳转回这个页面。
/// 该页面称作“返回页”,是同步被支付宝服务器所调用,可当作是支付完成后的提示信息页,如“您的某某某订单,多少金额已支付成功”。
/// </summary>
public partial class Alipay_Return : System.Web.UI.Page
{
    
protected void Page_Load(object sender, EventArgs e)
    {
        
if (!IsPostBack)
        {
            
//生成对象
            OfficeFinanceServices objOfficeFinanceServices = new OfficeFinanceServices();

            Alipaym objalipay 
= new Alipaym();

            
try
            {
                
string alipayNotifyURL = "https://www.alipay.com/cooperate/gateway.do?service=notify_verify";
                
//string alipayNotifyURL = "http://notify.alipay.com/trade/notify_query.do?";//此路径是在上面链接地址无法起作用时替换使用。
                string key = ""//partner 的对应交易安全校验码(必须填写)
                string partner = "";         //partner合作伙伴id(必须填写)
                string _input_charset = "utf-8";//编码类型,完全根据客户自身的项目的编码格式而定,千万不要填错。否则极其容易造成MD5加密错误。

                alipayNotifyURL 
= alipayNotifyURL + "&partner=" + partner + "&notify_id=" + Request.QueryString["notify_id"];

                
//获取支付宝ATN返回结果,true是正确的订单信息,false 是无效的
                string responseTxt = AliPay.Get_Http(alipayNotifyURL, 120000);

                
//*******加密签名程序开始//*******

                
int i;
                NameValueCollection coll;
                
//Load Form variables into NameValueCollection variable.
                coll = Request.QueryString;

                
// Get names of all forms into a string array.
                String[] requestarr = coll.AllKeys;

                
//进行排序;
                string[] Sortedstr = AliPay.BubbleSort(requestarr);

                
//构造待md5摘要字符串 ;
                StringBuilder prestr = new StringBuilder();

                
for (i = 0; i < Sortedstr.Length; i++)
                {
                    
if (Request.Form[Sortedstr[i]] != "" && Sortedstr[i] != "sign" && Sortedstr[i] != "sign_type")
                    {
                        
if (i == Sortedstr.Length - 1)
                        {
                            prestr.Append(Sortedstr[i] 
+ "=" + Request.QueryString[Sortedstr[i]]);
                        }
                        
else
                        {
                            prestr.Append(Sortedstr[i] 
+ "=" + Request.QueryString[Sortedstr[i]] + "&");
                        }
                    }
                }

                prestr.Append(key);

                
//生成Md5摘要;
                string mysign = AliPay.GetMD5(prestr.ToString(), _input_charset);
                
//*******加密签名程序结束*******

                
string sign = Request.QueryString["sign"];

                
//  Response.Write(prestr.ToString());  //调试用,支付宝服务器返回时的完整路径。
                if (mysign == sign && responseTxt == "true" && Request.UserHostName == "www.alipay.com")   //验证支付发过来的消息,签名是否正确
                {
                    
//更新自己数据库的订单语句,请自己填写一下
                    string strOrderNO = Request.QueryString["out_trade_no"];//订单号
                    string strPrice = Request.QueryString["total_fee"];//金额
                    string strTradeStatus = Request.QueryString["TRADE_STATUS"];//订单状态


                   

                    
 string result = objOfficeFinanceServices.CheckNo(strOrderNO.ToString().Trim());

                    
if (result.Trim() == "0")
                    {
                          
//成功,可美化该页面,提示信息

                        
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
                        string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + 
                            
",responseTxt=" + responseTxt ;
                        StreamWriter fs 
= new StreamWriter(Server.MapPath("Return_DATA/" + DateTime.Now.ToString().Replace(":""")) + ".txt"false, System.Text.Encoding.Default);
                        fs.Write(TOEXCELLR);
                        fs.Close();

                        
//修改订单状态

                        


                    }
                    
else if (result == "-1")
                    {
                        
//修改订单状态
                        ////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
                        string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt + "perky_" + result.Trim() + Request.UserHostName.Trim() + Request.UserHostAddress.Trim();
                        StreamWriter fs 
= new StreamWriter(Server.MapPath("Return_DATA/" + "e" + DateTime.Now.ToString().Replace(":""")) + ".txt"false, System.Text.Encoding.Default);
                        fs.Write(TOEXCELLR);
                        fs.Close();

                        Response.Write(
"查询订单时失败!!! 请确定你是否下单!!!");
                    }
                    
else
                    {
                        
//修改订单状态
                        ////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
                        string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt + "perky_" + result.Trim() + Request.UserHostName.Trim() + Request.UserHostAddress.Trim();
                        StreamWriter fs 
= new StreamWriter(Server.MapPath("Return_DATA/" + "e" + DateTime.Now.ToString().Replace(":""")) + ".txt"false, System.Text.Encoding.Default);
                        fs.Write(TOEXCELLR);
                        fs.Close();

                        Response.Write(
"重复使用界面无效!!!");
                    }
                }
                
else
                {
                    Response.Write(
"------------------------------------------");
                    Response.Write(
"<br>Result:responseTxt=" + responseTxt);
                    Response.Write(
"<br>Result:mysign=" + mysign);
                    Response.Write(
"<br>Result:sign=" + sign);
                    Response.Write(
"支付失败");


                    
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
                    string TOEXCELLR = "MD5结果:mysign=" + mysign + ",sign=" + sign + ",responseTxt=" + responseTxt + Request.UserHostName.Trim() + Request.UserHostAddress.Trim();
                    StreamWriter fs 
= new StreamWriter(Server.MapPath("Return_DATA/" + "e" + DateTime.Now.ToString().Replace(":""")) + ".txt"false, System.Text.Encoding.Default);
                    fs.Write(TOEXCELLR);
                    fs.Close();
                }
            }
            
catch (Exception ex)
            {
                
////写文本,纪录支付宝返回消息,比对md5计算结果(如网站不支持写txt文件,可改成写数据库)
                string TOEXCELLR = Request.Url.ToString() + "   " + ex.Message.ToString() + Request.UserHostName.Trim() + Request.UserHostAddress.Trim();
                StreamWriter fs 
= new StreamWriter(Server.MapPath("Return_DATA/" + "m" + DateTime.Now.ToString().Replace(":""")) + ".txt"false, System.Text.Encoding.Default);
                fs.Write(TOEXCELLR);
                fs.Close();
            }
        }
    }
}

Http的方法有的接口还是要带证书才能实现的

关于这一块的做方法大家请参考一下我的另一个文章

HttpRequest访问Https带有证书并使用WSDL文档生成代理类方案

地址:http://www.cnblogs.com/sufei/archive/2010/03/14/https.html 

 

应该注意的地方


 

      1.验证加密串

      2.验证首次加载时执行

      3.验证DNS或是IP

      4.IIS服务器绑定IP或是DNS

      5.一般要在关键的地方记录日志文件,或是存入数据库,要把发过来的请求原封不动的存储一下,一是方便查对,二是一但出现问题这就是证据啊!!!

      6.注意一下官方的加密串有没有统一大小写的问题