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. POJ 3169.Layout 最短路

    Layout Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11612   Accepted: 5550 Descripti ...

  2. readv writev示例程序

    当 readv() 时候,需要程序自己提供space,接收数据. #include <stdio.h> #include <stdlib.h> #include <str ...

  3. UI设计教程分享:Ps合成炫酷机械姬

    本次给大家分享一个通过PS合成一个炫酷的机械姬,在这个教程里给大家展示图像的色彩处理.人物光影塑造和创意实现及细节处理,教程比较简单,创意十足,看过<机械姬>电影的同学们一定知道这个有多炫 ...

  4. UI设计教程:如何在设计中运用颜色

    灰度优先 我们习惯在设计阶段的早期就开始调整颜色和色调.但是,当你意识到自己花了3个小时来调整主色调的时候,你发现这种行为毫无帮助.虽然把玩颜色很有吸引力,但是你应该避免在设计初期进行这种行为. 相反 ...

  5. start()方法和run()方法有什么区别?

    通过调用线程类的start()方法来启动一个线程,使线程处于就绪状态,即可以被JVM来调度执行,在调度过程中,JVM通过调用线程类的run()方法来完成实际的业务逻辑,当run()方法结束后,此线程就 ...

  6. Laravel 利用 observer 类基于状态属性,对进行删除和修改的控制

    1 我们知道 Observer 类可以监听模型类的相关事件 1.1 creating, created, updating, updated, saving, saved, deleting, del ...

  7. Https如何确保传输安全的

    1.对称加密算法 加密和解密算法是公开的,那个密钥是保密的, 只有双方才知道, 这样生成的加密消息(密文) 别人就无法得知了. 2.非对称加密算法 RSA算法非常有意思,是有一对儿钥匙, 一个是保密的 ...

  8. sql server profiler 工具使用 sql 语句性能分析

    https://www.cnblogs.com/knowledgesea/p/3683505.html

  9. hehe,网易邮箱已经流氓到这个地步了

    网易邮箱现在感觉作死,申请个邮箱还要下载你的APP,好,你牛逼,再见. 这是态度的问题. 最近丢了5亿的用户信息死不承认,撞库能把密保问题给撞出来? 如果真是撞库的话,丁三石养猪也已经感染口蹄疫了吧.

  10. 复制粘贴容易犯的错误 eclipse

    有时候复制原有的代码到xml文件中,会提示某文件没有找到,一般该文件名字改成别的了,这时候为了解决这问题一般需要对这个文件重命名