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;

 
 
好文要顶 关注我 收藏该文  
0
0
 
 
 
posted @ 2016-11-21 13:35 咏南 delphi 阅读(2361) 评论(0) 编辑 收藏

https://www.cnblogs.com/hnxxcxg/p/6085149.html的更多相关文章

  1. 访问路径:https://i.cnblogs.com/posts?categoryid=925678

    https://i.cnblogs.com/posts?categoryid=925678

  2. URL https://i.cnblogs.com/EditPosts.aspx?opt=1

    URL url = new URL("https://i.cnblogs.com");URL url1 = new URL(url, "EditPosts.aspx?op ...

  3. 随笔二-https://www.cnblogs.com/shang1680/p/9657994.html

    作业要求来自https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2097 GitHub远程仓库的地址:https://github.com/ ...

  4. 211806189杨昊辰 https://www.cnblogs.com/honey1433223/

    211806189杨昊辰 https://www.cnblogs.com/honey1433223/

  5. https://www.cnblogs.com/h2zZhou/p/5440271.html

    https://www.cnblogs.com/h2zZhou/p/5440271.html

  6. https://www.cnblogs.com/soundcode/p/4174410.html

    https://www.cnblogs.com/soundcode/p/4174410.html 1.首先要在服务器端新建一个网站axpx页 然后再网站的后台写代码获取winform传过来的文件名. ...

  7. https://www.cnblogs.com/yudanqu/p/9467803.html

    https://www.cnblogs.com/yudanqu/p/9467803.html

  8. 转发自:一像素 十大经典排序算法(动图演示)原链接:https://www.cnblogs.com/onepixel/articles/7674659.html 个人收藏所用 侵删

    原链接:https://www.cnblogs.com/onepixel/articles/7674659.html     个人收藏所用   侵删 0.算法概述 0.1 算法分类 十种常见排序算法可 ...

  9. @无痕客 https://www.cnblogs.com/wuhenke/archive/2012/12/24/2830530.html 通篇引用

    无痕客 https://www.cnblogs.com/wuhenke/archive/2012/12/24/2830530.html 关于Async与Await的FAQ 关于Async与Await的 ...

随机推荐

  1. EXISTS 和 IN 的区别

    exists子句的用法 select * from 表1 where exists (select * from 表2 where 表1.列名=表2.列名); exists子句返回的结果并不是从数据库 ...

  2. Java的反射技术

    什么是反射机制 Java的反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能调用它的任意属性和方法.这种动态获取信息以及动态调用对象属性和方法的即使称为J ...

  3. Java中的逆变与协变 很直接不饶弯的讲出来了

    ```java 协变 extends只能new 辈分比自己低的家伙 List<? extends Number> list001 = new ArrayList<Integer> ...

  4. c++11 时间相关操作练习

    博客和书籍资料 来自该地址 https://www.cnblogs.com/qicosmos/category/490693.html 自行编写相应代码进行学习 // TimeTest.cpp: 定义 ...

  5. 实现SQL express版做自动备份数据库的方法

    SQL Server 2005/2008 Express版没有代理组件,不支持维护计划.可以采用下面的办法实现每日备份: 一.在要备份的数据库中创建存储过程. 存储过程名称:sp_BackupData ...

  6. 关于Web应用开发流程的总结

    以下内容为个人工作总结,如果不当,谢谢指出错误. 假设最简单的情况,一个开发人员,开发所有的代码,一个测试人员.一个测试的服务器,一个生产的服务器. 开发人员需要为公司开发一个项目,开发人员首先分析产 ...

  7. MySQL中使用SHOW PROFILE命令分析性能的用法整理

    show profile是由Jeremy Cole捐献给MySQL社区版本的.默认的是关闭的,但是会话级别可以开启这个功能.开启它可以让MySQL收集在执行语句的时候所使用的资源.为了统计报表,把pr ...

  8. fabric 安装

    fabric 是一个python的库,fabric可以通过ssh批量管理服务器. 第一步安装依赖包 安装fabric依赖及pip yum install -y python-pip gcc pytho ...

  9. Codeforces 1107 简要题解

    文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 A题 传送门 题意简述:问你能不能把一个数字串切成若干块,使得切出来的kkk个数k≤2k\le2k≤2满足a1<a2<...&l ...

  10. 2019.01.24 bzoj3125: CITY(轮廓线dp)

    传送门 题意简述:给一个n∗mn*mn∗m的网格图,有的格子不能走,有的格子只能竖着走,有的格子只能横着走,问用一条回路覆盖所有能走的格子的方案数. 思路: 就是简单的轮廓线dpdpdp加了一点限制而 ...