Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
M
mall.oytour.com
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
黄奎
mall.oytour.com
Commits
4d6a2865
Commit
4d6a2865
authored
May 29, 2020
by
吴春
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
提交微信回调
parent
2f963457
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
323 additions
and
25 deletions
+323
-25
ResponseHandler.cs
Mall.Common/Pay/WeChatPat/ResponseHandler.cs
+41
-24
WeiXinHelper.cs
Mall.Common/Plugin/WeiXinHelper.cs
+183
-1
PayUtil.cs
Mall.WebApi/App_Code/PayUtil.cs
+99
-0
No files found.
Mall.Common/Pay/WeChatPat/ResponseHandler.cs
View file @
4d6a2865
using
Microsoft.AspNetCore.Http
;
using
Microsoft.AspNetCore.Http
;
using
Microsoft.AspNetCore.Http.Features
;
using
System
;
using
System
;
using
System.Collections
;
using
System.Collections
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Text
;
using
System.Xml
;
using
System.Xml
;
...
@@ -35,35 +37,50 @@ namespace Mall.Common.Pay.WeChatPat
...
@@ -35,35 +37,50 @@ namespace Mall.Common.Pay.WeChatPat
/// </summary>
/// </summary>
public
ResponseHandler
(
IHttpContextAccessor
_accessor
)
public
ResponseHandler
(
IHttpContextAccessor
_accessor
)
{
{
xmlMap
=
new
Hashtable
();
#
region
//注意:如果用以下读取流的方法,.net core 3.0 以后一定要加下边那段
//.net core 3.0以后需加下边这段,否则Stream会报错
var
syncIOFeature
=
_accessor
.
HttpContext
.
Features
.
Get
<
IHttpBodyControlFeature
>();
if
(
syncIOFeature
!=
null
)
{
syncIOFeature
.
AllowSynchronousIO
=
true
;
}
#
endregion
if
(
_accessor
.
HttpContext
.
Request
.
ContentLength
>
0
)
//接收从微信后台POST过来的数据
System
.
IO
.
Stream
s
=
_accessor
.
HttpContext
.
Request
.
Body
;
int
count
=
0
;
byte
[]
buffer
=
new
byte
[
1024
];
StringBuilder
builder
=
new
StringBuilder
();
while
((
count
=
s
.
Read
(
buffer
,
0
,
1024
))
>
0
)
{
{
var
reader
=
new
System
.
IO
.
StreamReader
(
_accessor
.
HttpContext
.
Request
.
Body
,
Encoding
.
UTF8
);
builder
.
Append
(
Encoding
.
UTF8
.
GetString
(
buffer
,
0
,
count
));
}
Plugin
.
LogHelper
.
Write
(
null
,
"Notify支付回调:reader-"
+
reader
.
ToString
());
s
.
Flush
();
_accessor
.
HttpContext
.
Request
.
Body
.
Position
=
0
;
s
.
Close
();
var
xmlDoc
=
new
XmlDocument
();
s
.
Dispose
();
xmlDoc
.
Load
(
reader
);
Plugin
.
LogHelper
.
Write
(
$"GetNotifyData Receive data from WeChat :
{
builder
.
ToString
()}
"
);
var
root
=
xmlDoc
.
SelectSingleNode
(
"xml"
);
var
xnl
=
root
.
ChildNodes
;
//转换数据格式并验证签名
foreach
(
XmlNode
xnf
in
xnl
)
// WxPayData data = new WxPayData();
try
{
XmlDocument
xmlDoc
=
new
XmlDocument
();
xmlDoc
.
LoadXml
(
builder
.
ToString
());
XmlNode
xmlNode
=
xmlDoc
.
FirstChild
;
//获取到根节点<xml>
XmlNodeList
nodes
=
xmlNode
.
ChildNodes
;
foreach
(
XmlNode
xn
in
nodes
)
{
{
xmlMap
.
Add
(
xn
f
.
Name
,
xnf
.
InnerText
);
xmlMap
.
Add
(
xn
.
Name
,
xn
.
InnerText
);
}
}
Plugin
.
LogHelper
.
Write
(
null
,
"Notify支付回调:xmlMap-"
+
xmlMap
.
ToString
());
}
}
//if (HttpContext.Current.Request.InputStream.Length > 0)
catch
(
Exception
ex
)
//{
{
// var xmlDoc = new XmlDocument();
//若签名错误,则立即返回结果给微信支付后台
// xmlDoc.Load(HttpContext.Current.Request.InputStream);
}
// var root = xmlDoc.SelectSingleNode("xml");
Plugin
.
LogHelper
.
Write
(
$"GetNotifyData Check sign success"
);
// var xnl = root.ChildNodes;
// foreach (XmlNode xnf in xnl)
// {
// xmlMap.Add(xnf.Name, xnf.InnerText);
// }
//}
}
}
/// <summary>
/// <summary>
...
...
Mall.Common/Plugin/WeiXinHelper.cs
View file @
4d6a2865
using
System
;
using
System
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Text
;
using
System.Text
;
using
System.Xml
;
namespace
Mall.Common.Plugin
namespace
Mall.Common.Plugin
{
{
public
class
WeiXinHelper
public
class
WeiXinHelper
{
{
}
}
/// <summary>
/// <summary>
...
@@ -69,4 +72,183 @@ namespace Mall.Common.Plugin
...
@@ -69,4 +72,183 @@ namespace Mall.Common.Plugin
public
string
errmsg
{
get
;
set
;
}
public
string
errmsg
{
get
;
set
;
}
}
}
#
endregion
#
endregion
}
public
class
WxPayData
{
public
const
string
SIGN_TYPE_MD5
=
"MD5"
;
public
const
string
SIGN_TYPE_HMAC_SHA256
=
"HMAC-SHA256"
;
public
WxPayData
()
{
}
//采用排序的Dictionary的好处是方便对数据包进行签名,不用再签名之前再做一次排序
private
SortedDictionary
<
string
,
object
>
m_values
=
new
SortedDictionary
<
string
,
object
>();
/**
* 设置某个字段的值
* @param key 字段名
* @param value 字段值
*/
public
void
SetValue
(
string
key
,
object
value
)
{
m_values
[
key
]
=
value
;
}
/**
* 根据字段名获取某个字段的值
* @param key 字段名
* @return key对应的字段值
*/
public
object
GetValue
(
string
key
)
{
object
o
=
null
;
m_values
.
TryGetValue
(
key
,
out
o
);
return
o
;
}
/**
* 判断某个字段是否已设置
* @param key 字段名
* @return 若字段key已被设置,则返回true,否则返回false
*/
public
bool
IsSet
(
string
key
)
{
object
o
=
null
;
m_values
.
TryGetValue
(
key
,
out
o
);
if
(
null
!=
o
)
return
true
;
else
return
false
;
}
/**
* @将Dictionary转成xml
* @return 经转换得到的xml串
* @throws WxPayException
**/
public
string
ToXml
()
{
//数据为空时不能转化为xml格式
if
(
0
==
m_values
.
Count
)
{
//_logger.LogError(this.GetType().ToString(), "WxPayData数据为空!");
throw
new
Exception
(
"WxPayData数据为空!"
);
}
string
xml
=
"<xml>"
;
foreach
(
KeyValuePair
<
string
,
object
>
pair
in
m_values
)
{
//字段值不能为null,会影响后续流程
if
(
pair
.
Value
==
null
)
{
//_logger.LogError(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
throw
new
Exception
(
"WxPayData内部含有值为null的字段!"
);
}
if
(
pair
.
Value
.
GetType
()
==
typeof
(
int
))
{
xml
+=
"<"
+
pair
.
Key
+
">"
+
pair
.
Value
+
"</"
+
pair
.
Key
+
">"
;
}
else
if
(
pair
.
Value
.
GetType
()
==
typeof
(
string
))
{
xml
+=
"<"
+
pair
.
Key
+
">"
+
"<![CDATA["
+
pair
.
Value
+
"]]></"
+
pair
.
Key
+
">"
;
}
else
//除了string和int类型不能含有其他数据类型
{
//_logger.LogError(this.GetType().ToString(), "WxPayData字段数据类型错误!");
throw
new
Exception
(
"WxPayData字段数据类型错误!"
);
}
}
xml
+=
"</xml>"
;
return
xml
;
}
public
SortedDictionary
<
string
,
object
>
NoSignFromXml
(
string
xml
)
{
if
(
string
.
IsNullOrEmpty
(
xml
))
{
//_logger.LogError(this.GetType().ToString(), "将空的xml串转换为WxPayData不合法!");
throw
new
Exception
(
"将空的xml串转换为WxPayData不合法!"
);
}
XmlDocument
xmlDoc
=
new
XmlDocument
();
xmlDoc
.
LoadXml
(
xml
);
XmlNode
xmlNode
=
xmlDoc
.
FirstChild
;
//获取到根节点<xml>
XmlNodeList
nodes
=
xmlNode
.
ChildNodes
;
foreach
(
XmlNode
xn
in
nodes
)
{
XmlElement
xe
=
(
XmlElement
)
xn
;
m_values
[
xe
.
Name
]
=
xe
.
InnerText
;
//获取xml的键值对到WxPayData内部的数据中
}
return
m_values
;
}
/**
* @Dictionary格式转化成url参数格式
* @ return url格式串, 该串不包含sign字段值
*/
public
string
ToUrl
()
{
string
buff
=
""
;
foreach
(
KeyValuePair
<
string
,
object
>
pair
in
m_values
)
{
if
(
pair
.
Value
==
null
)
{
//_logger.LogError(this.GetType().ToString(), "WxPayData内部含有值为null的字段!");
throw
new
Exception
(
"WxPayData内部含有值为null的字段!"
);
}
if
(
pair
.
Key
!=
"sign"
&&
pair
.
Value
.
ToString
()
!=
""
)
{
buff
+=
pair
.
Key
+
"="
+
pair
.
Value
+
"&"
;
}
}
buff
=
buff
.
Trim
(
'&'
);
return
buff
;
}
public
bool
CheckSign
()
{
////如果没有设置签名,则跳过检测
//if (!IsSet("sign"))
//{
// //_logger.LogError(this.GetType().ToString(), "WxPayData签名存在但不合法!");
// throw new Exception("WxPayData签名存在但不合法!");
//}
////如果设置了签名但是签名为空,则抛异常
//else if (GetValue("sign") == null || GetValue("sign").ToString() == "")
//{
// //_logger.LogError(this.GetType().ToString(), "WxPayData签名存在但不合法!");
// throw new Exception("WxPayData签名存在但不合法!");
//}
////获取接收到的签名
//string return_sign = GetValue("sign").ToString();
////在本地计算新的签名
//string cal_sign = payReq.CreateMd5Sign(_accessor, model.WeChatApiSecret);
return
true
;
//if (cal_sign == return_sign)
//{
// return true;
//}
//_logger.LogError(this.GetType().ToString(), "WxPayData签名验证错误!");
throw
new
Exception
(
"WxPayData签名验证错误!"
);
}
}
}
Mall.WebApi/App_Code/PayUtil.cs
View file @
4d6a2865
...
@@ -17,6 +17,7 @@ using Mall.Common;
...
@@ -17,6 +17,7 @@ using Mall.Common;
using
Mall.Model.Extend.User
;
using
Mall.Model.Extend.User
;
using
NPOI.SS.Formula.Functions
;
using
NPOI.SS.Formula.Functions
;
using
Org.BouncyCastle.Utilities.Net
;
using
Org.BouncyCastle.Utilities.Net
;
using
Microsoft.AspNetCore.Http.Features
;
namespace
Mall.WebApi.App_Code
namespace
Mall.WebApi.App_Code
{
{
...
@@ -199,6 +200,104 @@ namespace Mall.WebApi.App_Code
...
@@ -199,6 +200,104 @@ namespace Mall.WebApi.App_Code
//public ProcessNotify(HttpContext context)
//{
// WxPayData notifyData = GetNotifyData(context);
// //检查支付结果中transaction_id是否存在
// if (!notifyData.IsSet("transaction_id"))
// {
// //若transaction_id不存在,则立即返回结果给微信支付后台
// WxPayData res = new WxPayData();
// res.SetValue("return_code", "FAIL");
// res.SetValue("return_msg", "支付结果中微信订单号不存在");
// context.Response.WriteAsync(res.ToXml());
// return (false, null);
// }
// string transaction_id = notifyData.GetValue("transaction_id").ToString();
// string out_trade_no = notifyData.GetValue("out_trade_no").ToString();
// //查询订单,判断订单真实性
// if (!QueryOrder(transaction_id))
// {
// //若订单查询失败,则立即返回结果给微信支付后台
// WxPayData res = new WxPayData();
// res.SetValue("return_code", "FAIL");
// res.SetValue("return_msg", "订单查询失败");
// context.Response.WriteAsync(res.ToXml());
// return (false, null);
// }
// //查询订单成功
// else
// {
// WxPayData res = new WxPayData();
// res.SetValue("return_code", "SUCCESS");
// res.SetValue("return_msg", "OK");
// context.Response.WriteAsync(res.ToXml());
// ProcessNotifyReturn notifyReturn = new ProcessNotifyReturn
// {
// out_trade_no = out_trade_no,
// transaction_id = transaction_id
// };
// return (true, notifyReturn);
// }
//}
///// <summary>
///// 接收从微信支付后台发送过来的数据并验证签名
///// </summary>
///// <returns>微信支付后台返回的数据</returns>
//public WxPayData GetNotifyData(HttpContext context)
//{
// #region
// //注意:如果用以下读取流的方法,.net core 3.0 以后一定要加下边那段
// //.net core 3.0以后需加下边这段,否则Stream会报错
// var syncIOFeature = context.Features.Get<IHttpBodyControlFeature>();
// if (syncIOFeature != null)
// {
// syncIOFeature.AllowSynchronousIO = true;
// }
// #endregion
// //接收从微信后台POST过来的数据
// System.IO.Stream s = context.Request.Body;
// int count = 0;
// byte[] buffer = new byte[1024];
// StringBuilder builder = new StringBuilder();
// while ((count = s.Read(buffer, 0, 1024)) > 0)
// {
// builder.Append(Encoding.UTF8.GetString(buffer, 0, count));
// }
// s.Flush();
// s.Close();
// s.Dispose();
// LogHelper.Write($"GetNotifyData Receive data from WeChat :{builder.ToString()}");
// //转换数据格式并验证签名
// WxPayData data = new WxPayData();
// try
// {
// data.FromXml(builder.ToString());
// }
// catch (Exception ex)
// {
// //若签名错误,则立即返回结果给微信支付后台
// WxPayData res = new WxPayData();
// res.SetValue("return_code", "FAIL");
// res.SetValue("return_msg", ex.Message);
// context.Response.WriteAsync(res.ToXml());
// }
// LogHelper.Write($"GetNotifyData Check sign success");
// return data;
//}
// <summary>
// <summary>
/// 退款 传入订单号OrderNumber,RefundNumber,总金额total_fee(分),RefundFee退款金额(分),
/// 退款 传入订单号OrderNumber,RefundNumber,总金额total_fee(分),RefundFee退款金额(分),
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment