• DELPHI微信支付代码


    DELPHI微信支付代码

     

    不管是微信支付还是支付宝支付, 3个最棘手的问题是:
    1,如何生成签名
    2,支付请求如何提交
    3, 如何验证签名

    下面就围绕这二个问题来讲。

    我使用的是XE3.

    先看微信支付:
    1,微信支付的签名生成

    uses IdHashMessageDigest, NatvieXml; //我使用的是NativeXml4.07

    function TMicroPayParamBuilder.GetSign: string;
    var
    Digest: TIdHashMessageDigest5;
    utf8: UTF8String;
    begin
    utf8 := '';

    Assert(FAppId <> '', '公众账号ID 不能为空!');
    utf8 := utf8 + 'appid=' + FAppId;

    if FAttach <> '' then
    utf8 := utf8 + '&attach=' + FAttach;

    Assert(FAuthCode <> '', '授权码 不能为空!');
    utf8 := utf8 + '&auth_code=' + FAuthCode;

    Assert(FBody <> '', '商品描述 不能为空!');
    utf8 := utf8 + '&body=' + FBody;

    if FDetail <> '' then
    utf8 := utf8 + '&detail=' + BuildDetail();

    Assert(FMchId <> '', '商户号 不能为空!');
    utf8 := utf8 + '&mch_id=' + FMchId;

    utf8 := utf8 + '&nonce_str=' + FNonceStr;

    Assert(FOutTradeNo <> '', '商户订单号 不能为空!');
    utf8 := utf8 + '&out_trade_no=' + FOutTradeNo;

    Assert(FSpbillCreateIp <> '', '终端IP 不能为空!');
    utf8 := utf8 + '&spbill_create_ip=' + FSpbillCreateIp;

    Assert(FTotalFee > 0, '订单金额 必须大于0!');
    utf8 := utf8 + '&total_fee=' + IntToStr(FTotalFee);

    Assert(Fkey <> '', '密钥 不能为空!');
    utf8 := utf8 + '&key=' + Fkey;

    //计算签名
    try
    Digest:= TIdHashMessageDigest5.Create;
    Result := Digest.HashBytesAsHex(BytesOf(utf8));
    finally
    Digest.Free;
    end;
    end;

    //生成Http Post请求的数据
    function TMicroPayParamBuilder.BuildParam: string;
    var
    xml : TNativeXml;
    Node: TXmlNode;
    begin
    xml := TNativeXml.CreateEx(nil, False, False, True, 'xml');
    try
    Node:= xml.NodeNewTextType('appid', FAppId , xeElement);
    xml.Root.NodeAdd(Node);

    Node:= xml.NodeNewTextType('mch_id', FMchId , xeElement);
    xml.Root.NodeAdd(Node);


    Node:= xml.NodeNewTextType('nonce_str', FNonceStr , xeElement);
    xml.Root.NodeAdd(Node);

    Node:= xml.NodeNewTextType('sign', Sign , xeElement);
    xml.Root.NodeAdd(Node);

    Node:= xml.NodeNewTextType('body', FBody , xeElement);
    xml.Root.NodeAdd(Node);

    Node:= xml.NodeNewTextType('out_trade_no', FOutTradeNo , xeElement);
    xml.Root.NodeAdd(Node);

    Node:= xml.NodeNewIntType('total_fee', FTotalFee , xeElement);
    xml.Root.NodeAdd(Node);

    Node:= xml.NodeNewTextType('spbill_create_ip', FSpbillCreateIp , xeElement);
    xml.Root.NodeAdd(Node);

    Node:= xml.NodeNewTextType('auth_code', FAuthCode , xeElement);
    xml.Root.NodeAdd(Node);

    if FAttach <> '' then
    begin
    Node:= xml.NodeNewTextType('attach', FAttach , xeElement);
    xml.Root.NodeAdd(Node);
    end;

    if FDetail <> '' then
    begin
    Node:= xml.NodeNewTextType('detail', BuildDetail() , xeElement);
    xml.Root.NodeAdd(Node);
    end;

    Result := xml.WriteToString;

    finally
    xml.Free;
    end;
    end;

    2, 微信支付请求如何提交 
    class function TTencentSSLHttpPost.Post(URL: string;
    Builder: TBaseParamBuilder): string;
    var
    ssl:TIdSSLIOHandlerSocketOpenSSL;
    http: TIdHttp;
    inStrm, outStrm: TStringStream;
    begin
    http:= TIdHttp.Create(nil);
    ssl:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
    ssl.SSLOptions.Method := sslvSSLv23;
    http.IOHandler := ssl;
    inStrm:= TStringStream.Create(Builder.BuildParam, TEncoding.UTF8);
    outStrm:= TStringStream.Create('', TEncoding.UTF8);
    try
    try
    http.Post(URL, inStrm, outStrm);
    Result := outStrm.DataString;

    except
    Result := '';
    end;
    finally
    ssl.Free;
    http.Free;
    outStrm.Free;
    inStrm.Free;
    end;
    end;

    const URL_MicroPay = 'https://api.mch.weixin.qq.com/pay/micropay';

    class function TMicroPayHttpUtils.PostRequest( Builder: TMicroPayParamBuilder): string;
    begin Result := TTencentSSLHttpPost.Post(URL_MicroPay, Builder);
    end;

    微信如何验证签名:

    TStringsHelper = class helper for TStrings
    function Join(const Splitter: string): string;
    end;

    { TMyStrings}

    function TStringsHelper.Join(const Splitter: string): string;
    var
    I : Integer;
    begin
    Result := '';
    for I := 0 to Self.Count - 1 do
    Result := Result + Splitter + Self.Names[I] + '=' + Self.ValueFromIndex[I];

    if Result <> '' then System.Delete(result, 1, Length(Splitter));
    end;

    function MyStringListSort(List: TStringList; Index1, Index2: Integer): Integer;
    begin
    Result := CompareStr(List.Names[Index1], List.Names[Index2]);
    end;

    function VerifyResponseSign(xml: TNativeXml; Key: string): Boolean; overload;
    var
    sign: string;
    I : Integer;
    List : TStringList;
    utf8: UTF8String;
    Digest: TIdHashMessageDigest5;
    begin
    Result := False;

    if xml.Root.FindNode('sign') = nil then Exit;
    sign := xml.Root.FindNode('sign').ValueUnicode;

    List := TStringList.Create;
    try
    for I := 0 to xml.Root.NodeCount - 1 do
    begin
    if (xml.Root.Nodes[I].NameUnicode <> 'sign') and (xml.Root.Nodes[I].NameUnicode <> 'WhiteSpace')
    and (xml.Root.Nodes[I].ValueUnicode <> '') then
    List.Add(xml.Root.Nodes[I].NameUnicode + '=' + xml.Root.Nodes[I].ValueUnicode);
    end;
    List.CustomSort(MyStringListSort);

    utf8 := List.Join('&') + '&key=' + key;

    try
    Digest:= TIdHashMessageDigest5.Create;
    Result := SameText(Digest.HashBytesAsHex(BytesOf(utf8)), sign);
    finally
    Digest.Free;
    end;
    finally
    List.Free;
    end;
    end;

    function VerifyResponseSign(xml: TNativeXml): Boolean; overload;
    begin
    Result := VerifyResponseSign(xml, GetKey());
    end;

    function VerifyResponseSign(Response: string; Key: string): Boolean; overload;
    var
    xml: TNativeXml;
    begin
    Result := False;
    xml := TNativeXml.Create(nil);
    try
    try
    xml.ReadFromString(Response);
    except
    Exit;
    end;

    Result := VerifyResponseSign(xml, Key);
    finally
    xml.Free;
    end;
    end; 

    那么如何发送一个刷卡支付请求呢?
    procedure TForm4.btn4Click(Sender: TObject);
    var
    Param: TMicroPayParamBuilder;
    Response: string;
    begin
    Param:= TMicroPayParamBuilder.Create;
    try
    if edBody.Text <> '' then
    Param.Body := edBody.Text;
    Param.OutTradeNo:= edTradeNo.Text;
    Param.SpbillCreateIp:=idpwtch1.LocalIP;
    param.AuthCode:= edAuthCode.Text;
    Param.Attach := edAttach.Text;
    Param.TotalFee := 10;

    param.AppId := edAppId.Text;
    Param.MchId := edMch_id.Text;
    Param.Key := edKey.Text;

    mmo1.Lines.Append(Param.BuildParam);
    mmo1.Lines.Append('-------------------------------------------');

    Response := TMicroPayHttpUtils.PostRequest(Param);

    if Response = '' then
    begin
    ShowMessage('请求出错! 可能是网络不通!');
    Exit;
    end;

    mmo1.Lines.Append(Response);

    if not VerifyResponseSign(Response, GetKey()) then 
    showmessage('签名验证不通过!');

    finally
    Param.Free;
    end;
    end;

  • 相关阅读:
    Eclipse使用jre的原理与配置
    [笔记]Android开发环境配置及HelloWorld程序
    【足迹C++primer】38、关联容器操作(2)
    Linux ls 命令实现(简化版)
    POJ1149_PIGS(网络流/EK)
    调用存储过程取到数据通过NPOI存到Excel中
    python get post模拟请求
    常见软件应用
    Docker 镜像的导入和导出
    Linux 编译安装R语言
  • 原文地址:https://www.cnblogs.com/westsoft/p/9107643.html
Copyright © 2020-2023  润新知