Commit 423a1861 authored by 吴春's avatar 吴春

支付

parent ef4aec86
......@@ -330,5 +330,19 @@ namespace Mall.Common
return new ConfigurationBuilder().Add(new JsonConfigurationSource { Path = "appsettings.json" }).Build().GetSection("ByteDanceSendTemplate").Value;
}
}
/// <summary>
/// 微信支付成功接口处理地址
/// </summary>
public static string sTenpayNotify
{
get
{
return new ConfigurationBuilder().Add(new JsonConfigurationSource { Path = "appsettings.json" }).Build().GetSection("sTenpayNotify").Value;
}
}
}
}
\ No newline at end of file
......@@ -4,8 +4,19 @@
<TargetFramework>netcoreapp3.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Pay\Alipay\**" />
<EmbeddedResource Remove="Pay\Alipay\**" />
<None Remove="Pay\Alipay\**" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Pay\WeChatPat\Model\WeChatConfig.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.0.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
......
using System.Web;
using System.Text;
using System.IO;
using System.Net;
using System;
using System.Collections.Generic;
namespace Mall.Common.Pay.Alipay
{
/// <summary>
/// 类名:Config
/// 功能:基础配置类
/// 详细:设置帐户有关信息及返回路径
/// 版本:3.3
/// 日期:2012-07-05
/// 说明:
/// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
/// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
///
/// 如何获取安全校验码和合作身份者ID
/// 1.用您的签约支付宝账号登录支付宝网站(www.alipay.com)
/// 2.点击“商家服务”(https://b.alipay.com/order/myOrder.htm)
/// 3.点击“查询合作者身份(PID)”、“查询安全校验码(Key)”
/// </summary>
public class Config
{
#region 字段
private static string partner = "";
private static string key = "";
private static string androidlkey = "";
private static string input_charset = "";
private static string sign_type = "";
#endregion
static Config()
{
//↓↓↓↓↓↓↓↓↓↓请在这里配置您的基本信息↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
//合作身份者ID,以2088开头由16位纯数字组成的字符串
partner = "";// Common.Config.GetAppSetting("AlipayID");
//"2088211806203122";
//交易安全检验码,由数字和字母组成的32位字符串
key = ""; //Common.Config.GetAppSetting("AlipayKey"); //"sddstgxfj2skw483v1vj6kfb89qengin";
androidlkey = "";// Common.Config.GetAppSetting("AlipayPublicKey");
//字符编码格式 目前支持 gbk 或 utf-8
input_charset = "utf-8";
//签名方式,选择项:RSA、DSA、MD5
//sign_type = "MD5";
sign_type = "RSA";
}
#region 属性
/// <summary>
/// 获取或设置合作者身份ID
/// </summary>
public static string Partner
{
get { return partner; }
set { partner = value; }
}
/// <summary>
/// 获取或设交易安全校验码
/// </summary>
public static string Key
{
get { return key; }
set { key = value; }
}
/// <summary>
/// 获取或设安卓端交易安全校验码
/// </summary>
public static string AndroidKey
{
get { return androidlkey; }
set { androidlkey = value; }
}
/// <summary>
/// 获取字符编码格式
/// </summary>
public static string Input_charset
{
get { return input_charset; }
}
/// <summary>
/// 获取签名方式
/// </summary>
public static string Sign_type
{
get { return sign_type; }
}
#endregion
}
}
\ No newline at end of file
using System.Web;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Net;
using System;
using System.Collections.Generic;
using System.Xml;
namespace Mall.Common.Pay.Alipay
{
/// <summary>
/// 类名:Core
/// 功能:支付宝接口公用函数类
/// 详细:该类是请求、通知返回两个文件所调用的公用函数核心处理文件,不需要修改
/// 版本:3.3
/// 修改日期:2012-07-05
/// 说明:
/// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
/// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
/// </summary>
public class Core
{
/// <summary>
/// 构造函数
/// </summary>
public Core()
{
}
/// <summary>
/// 除去数组中的空值和签名参数并以字母a到z的顺序排序
/// </summary>
/// <param name="dicArrayPre">过滤前的参数组</param>
/// <returns>过滤后的参数组</returns>
public static Dictionary<string, string> FilterPara(SortedDictionary<string, string> dicArrayPre)
{
Dictionary<string, string> dicArray = new Dictionary<string, string>();
foreach (KeyValuePair<string, string> temp in dicArrayPre)
{
if (temp.Key.ToLower() != "sign" && temp.Key.ToLower() != "sign_type" && temp.Value != "" && temp.Value != null)
{
dicArray.Add(temp.Key, temp.Value);
}
}
return dicArray;
}
/// <summary>
/// 把数组所有元素,按照“参数=参数值”的模式用字符拼接成字符串
/// </summary>
/// <param name="dicArray">需要拼接的数组</param>
/// <returns>拼接完成以后的字符串</returns>
public static string CreateLinkString(Dictionary<string, string> dicArray)
{
StringBuilder prestr = new StringBuilder();
foreach (KeyValuePair<string, string> temp in dicArray)
{
prestr.Append(temp.Key + "=" + temp.Value + "&");
}
//去掉最後一個&字符
int nLen = prestr.Length;
prestr.Remove(nLen-1,1);
return prestr.ToString();
}
/// <summary>
/// 把数组所有元素,按照“参数=参数值”的模式用字符拼接成字符串,并对参数值做urlencode
/// </summary>
/// <param name="dicArray">需要拼接的数组</param>
/// <param name="code">字符编码</param>
/// <returns>拼接完成以后的字符串</returns>
public static string CreateLinkStringUrlencode(Dictionary<string, string> dicArray, Encoding code)
{
StringBuilder prestr = new StringBuilder();
foreach (KeyValuePair<string, string> temp in dicArray)
{
prestr.Append(temp.Key + "=" + HttpUtility.UrlEncode(temp.Value, code) + "&");
}
//去掉最後一個&字符
int nLen = prestr.Length;
prestr.Remove(nLen - 1, 1);
return prestr.ToString();
}
/// <summary>
/// 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
/// </summary>
/// <param name="sWord">要写入日志里的文本内容</param>
public static void LogResult(string sWord)
{
string strPath = HttpContext.Current.Server.MapPath("log");
strPath = strPath + "\\" + DateTime.Now.ToString().Replace(":", "") + ".txt";
StreamWriter fs = new StreamWriter(strPath, false, System.Text.Encoding.Default);
fs.Write(sWord);
fs.Close();
}
/// <summary>
/// 获取文件的md5摘要
/// </summary>
/// <param name="sFile">文件流</param>
/// <returns>MD5摘要结果</returns>
public static string GetAbstractToMD5(Stream sFile)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(sFile);
StringBuilder sb = new StringBuilder(32);
for (int i = 0; i < result.Length; i++)
{
sb.Append(result[i].ToString("x").PadLeft(2, '0'));
}
return sb.ToString();
}
/// <summary>
/// 获取文件的md5摘要
/// </summary>
/// <param name="dataFile">文件流</param>
/// <returns>MD5摘要结果</returns>
public static string GetAbstractToMD5(byte[] dataFile)
{
MD5 md5 = new MD5CryptoServiceProvider();
byte[] result = md5.ComputeHash(dataFile);
StringBuilder sb = new StringBuilder(32);
for (int i = 0; i < result.Length; i++)
{
sb.Append(result[i].ToString("x").PadLeft(2, '0'));
}
return sb.ToString();
}
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
namespace Mall.Common.Pay.Alipay
{
/// <summary>
/// 支付宝帮助类
/// </summary>
public class AlipayHelp
{
/// <summary>
/// 创建支付宝url
/// </summary>
/// <param name="sOrderNo">订单编号</param>
/// <param name="sOrderName">订单名称</param>
/// <param name="sMoney">金额</param>
/// <param name="sOrderDescription">订单描述</param>
/// <param name="sNotifyUrl">服务器异步通知页面路径</param>
/// <param name="sReturnUrl">页面跳转同步通知页面路径</param>
/// <param name="bIsFormSubmit"></param>
/// <returns></returns>
public static string CreateAlipayUrl(string sOrderNo, string sOrderName, string sMoney,
string sOrderDescription, string sNotifyUrl, string sReturnUrl, bool bIsFormSubmit = true)
{
#region 创建支付宝url
string GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";
string payment_type = "1";
//必填,不能修改
//服务器异步通知页面路径
string notify_url = "http://" + HttpContext.Current.Request.Url.Authority + sNotifyUrl;
//需http://格式的完整路径,不能加?id=123这类自定义参数
//页面跳转同步通知页面路径
string return_url = "http://" + HttpContext.Current.Request.Url.Authority + sReturnUrl;
//需http://格式的完整路径,不能加?id=123这类自定义参数,不能写成http://localhost/
//卖家支付宝帐户
string seller_email = Common.Config.GetAppSetting("AlipayName"); //"AlipayName".ReadConfig();
//必填
//商户订单号
string out_trade_no = sOrderNo;
//商户网站订单系统中唯一订单号,必填
//订单名称
string subject = sOrderName;
//必填
//付款金额
string total_fee = sMoney;
//必填
//订单描述
string body = sOrderDescription;
//商品展示地址
string show_url = "";
//需以http://开头的完整路径,例如:http://www.xxx.com/myorder.html
//防钓鱼时间戳
string anti_phishing_key = "";
//若要使用请调用类文件submit中的query_timestamp函数
//客户端的IP地址
string exter_invoke_ip = "";//Function.NetIP();
//非局域网的外网IP地址,如:221.0.0.1
////////////////////////////////////////////////////////////////////////////////////////////////
//把请求参数打包成数组
SortedDictionary<string, string> sParaTemp = new SortedDictionary<string, string>
{
{ "partner", Config.Partner },
{ "_input_charset", Config.Input_charset.ToLower() },
{ "service", "create_direct_pay_by_user" },
{ "payment_type", payment_type },
{ "notify_url", notify_url },
{ "return_url", return_url },
{ "seller_email", seller_email },
{ "out_trade_no", out_trade_no },
{ "subject", subject },
{ "total_fee", total_fee },
{ "body", body },
{ "show_url", show_url },
{ "anti_phishing_key", anti_phishing_key },
{ "exter_invoke_ip", exter_invoke_ip }
};
//建立请求
string sHtmlText = string.Empty;
if (bIsFormSubmit)
sHtmlText = Submit.BuildRequest(GATEWAY_NEW, sParaTemp, "Get", "提交");
else
sHtmlText = Submit.BuildUrl(GATEWAY_NEW, sParaTemp);
return sHtmlText;
#endregion
}
/// <summary>
/// 支付宝app支付
/// </summary>
/// <param name="sOrderNo">订单编号</param>
/// <param name="sProductName">产品名称</param>
/// <param name="dPrice">价格</param>
/// <param name="CustomerId">客户编号</param>
/// <returns></returns>
public static string AppPayRequest(string sOrderNo, string sProductName, decimal dPrice, string CustomerId)
{
string orderInfo = string.Empty;
// string FilialeIdStr = Common.Config.GetAppSetting("FilialeId");//分公司总经理岗位id
// 签约合作者身份ID
//orderInfo = "partner=" + "\"" + "AlipayID".ReadConfig() + "\"";
orderInfo = "partner=" + "\"" + Common.Config.GetAppSetting("AlipayID") + "\"";
// 签约卖家支付宝账号
//orderInfo += "&seller_id=" + "\"" + "AlipayName".ReadConfig() + "\"";
orderInfo += "&seller_id=" + "\"" + Common.Config.GetAppSetting("AlipayName") + "\"";
// 商户网站唯一订单号
orderInfo += "&out_trade_no=" + "\"" + sOrderNo + "\"";
// 商品名称
orderInfo += "&subject=\"" + "支付订单" + "\"";
// 商品详情
orderInfo += "&body=" + "\"" + sProductName + "\"";
// 商品金额
orderInfo += "&total_fee=" + "\"" + dPrice + "\"";
// 服务器异步通知页面路径
//orderInfo += "&notify_url=" + "\"" + "AlipayPayNotifyUrl".ReadConfig() + "\"";
orderInfo += "&notify_url=" + "\"" + Common.Config.GetAppSetting("AlipayPayNotifyUrl") + "\"";
// 服务接口名称, 固定值
orderInfo += "&service=\"mobile.securitypay.pay\"";
// 支付类型, 固定值
orderInfo += "&payment_type=\"1\"";
// 参数编码, 固定值
orderInfo += "&_input_charset=\"utf-8\"";
// 设置未付款交易的超时时间
// 默认30分钟,一旦超时,该笔交易就会自动被关闭。
// 取值范围:1m~15d。
// m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
// 该参数数值不接受小数点,如1.5h,可转换为90m。
orderInfo += "&it_b_pay=\"30m\"";
// extern_token为经过快登授权获取到的alipay_open_id,带上此参数用户将使用授权的账户进行支付
// orderInfo += "&extern_token=" + "\"" + extern_token + "\"";
// 支付宝处理完请求后,当前页面跳转到商户指定页面的路径,可空
orderInfo += "&return_url=\"m.alipay.com\"";
// 调用银行卡支付,需配置此参数,参与签名, 固定值 (需要签约《无线银行卡快捷支付》才能使用)
// orderInfo += "&paymethod=\"expressGateway\"";
// return "{ \"sOrderInfo\":\"" + HttpUtility.UrlEncode(orderInfo) + "\",\"AlipayPrivateKey\":\"" + "AlipayPrivateKey".ReadConfig() + "\"}";
return "{ \"sOrderInfo\":\"" + HttpUtility.UrlEncode(orderInfo) + "\",\"AlipayPrivateKey\":\"" + Common.Config.GetAppSetting("AlipayPrivateKey") + "\"}";
}
/// <summary>
/// 获取支付宝POST过来通知消息,并以“参数名=参数值”的形式组成数组
/// </summary>
/// <returns>request回来的信息组成的数组</returns>
public static SortedDictionary<string, string> GetRequestPost()
{
#region 获取支付宝POST过来通知消息,并以“参数名=参数值”的形式组成数组
int i = 0;
SortedDictionary<string, string> sArray = new SortedDictionary<string, string>();
NameValueCollection coll;
//Load Form variables into NameValueCollection variable.
coll = HttpContext.Current.Request.Form;
// Get names of all forms into a string array.
String[] requestItem = coll.AllKeys;
for (i = 0; i < requestItem.Length; i++)
{
sArray.Add(requestItem[i], HttpContext.Current.Request.Form[requestItem[i]]);
}
return sArray;
#endregion
}
/// <summary>
/// 获取支付宝GET过来通知消息,并以“参数名=参数值”的形式组成数组
/// </summary>
/// <returns>request回来的信息组成的数组</returns>
public static SortedDictionary<string, string> GetRequestGet()
{
#region 获取支付宝GET过来通知消息,并以“参数名=参数值”的形式组成数组
int i = 0;
SortedDictionary<string, string> sArray = new SortedDictionary<string, string>();
NameValueCollection coll;
//Load Form variables into NameValueCollection variable.
coll = HttpContext.Current.Request.QueryString;
// Get names of all forms into a string array.
String[] requestItem = coll.AllKeys;
for (i = 0; i < requestItem.Length; i++)
{
sArray.Add(requestItem[i], HttpContext.Current.Request.QueryString[requestItem[i]]);
}
return sArray;
#endregion
}
}
}
\ No newline at end of file
using System.Web;
using System.Text;
using System.IO;
using System.Net;
using System;
using System.Collections.Generic;
namespace Mall.Common.Pay.Alipay
{
/// <summary>
/// 类名:Notify
/// 功能:支付宝通知处理类
/// 详细:处理支付宝各接口通知返回
/// 版本:3.3
/// 修改日期:2011-07-05
/// '说明:
/// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
/// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
///
/// //////////////////////注意/////////////////////////////
/// 调试通知返回时,可查看或改写log日志的写入TXT里的数据,来检查通知返回是否正常
/// </summary>
public class Notify
{
#region 字段
private string _partner = ""; //合作身份者ID
private string _key = ""; //商户的私钥
private string _androidlkey = "";
private string _input_charset = ""; //编码格式
private string _sign_type = ""; //签名方式
//支付宝消息验证地址
private string Https_veryfy_url = "https://mapi.alipay.com/gateway.do?service=notify_verify&";
#endregion
/// <summary>
/// 构造函数
/// 从配置文件中初始化变量
/// </summary>
public Notify()
{
//初始化基础配置信息
_partner = Config.Partner.Trim();
_key = Config.Key.Trim();
_androidlkey = Config.AndroidKey.Trim();
_input_charset = Config.Input_charset.Trim().ToLower();
// _sign_type = Config.Sign_type.Trim().ToUpper();
}
/// <summary>
/// 验证消息是否是支付宝发出的合法消息
/// </summary>
/// <param name="inputPara">通知返回参数数组</param>
/// <param name="notify_id">通知验证ID</param>
/// <param name="sign">支付宝生成的签名结果</param>
/// <returns>验证结果</returns>
public bool Verify(SortedDictionary<string, string> inputPara, string notify_id, string sign)
{
//获取返回时的签名验证结果
bool isSign = GetSignVeryfy(inputPara, sign);
//获取是否是支付宝服务器发来的请求的验证结果
string responseTxt = "true";
if (notify_id != null && notify_id != "") { responseTxt = GetResponseTxt(notify_id); }
//写日志记录(若要调试,请取消下面两行注释)
//string sWord = "responseTxt=" + responseTxt + "\n isSign=" + isSign.ToString() + "\n 返回回来的参数:" + GetPreSignStr(inputPara) + "\n ";
//Core.LogResult(sWord);
//判断responsetTxt是否为true,isSign是否为true
//responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (responseTxt == "true" && isSign)//验证成功
{
return true;
}
else//验证失败
{
return false;
}
}
/// <summary>
/// 获取待签名字符串(调试用)
/// </summary>
/// <param name="inputPara">通知返回参数数组</param>
/// <returns>待签名字符串</returns>
private string GetPreSignStr(SortedDictionary<string, string> inputPara)
{
Dictionary<string, string> sPara = new Dictionary<string, string>();
//过滤空值、sign与sign_type参数
sPara = Core.FilterPara(inputPara);
//获取待签名字符串
string preSignStr = Core.CreateLinkString(sPara);
return preSignStr;
}
/// <summary>
/// 获取返回时的签名验证结果
/// </summary>
/// <param name="inputPara">通知返回参数数组</param>
/// <param name="sign">对比的签名结果</param>
/// <returns>签名验证结果</returns>
private bool GetSignVeryfy(SortedDictionary<string, string> inputPara, string sign)
{
Dictionary<string, string> sPara = new Dictionary<string, string>();
//过滤空值、sign与sign_type参数
sPara = Core.FilterPara(inputPara);
//获取待签名字符串
string preSignStr = Core.CreateLinkString(sPara);
_sign_type = inputPara["sign_type"].ToUpper();
//获得签名验证结果
bool isSgin = false;
if (sign != null && sign != "")
{
switch (_sign_type)
{
default:
case "MD5":
isSgin = AlipayMD5.Verify(preSignStr, sign, _key, _input_charset);
break;
case "RSA":
isSgin = RSAFromPkcs8.verify(preSignStr, sign, _androidlkey, _input_charset);
break;
}
}
return isSgin;
}
/// <summary>
/// 获取是否是支付宝服务器发来的请求的验证结果
/// </summary>
/// <param name="notify_id">通知验证ID</param>
/// <returns>验证结果</returns>
private string GetResponseTxt(string notify_id)
{
string veryfy_url = Https_veryfy_url + "partner=" + _partner + "&notify_id=" + notify_id;
//获取远程服务器ATN结果,验证是否是支付宝服务器发来的请求
string responseTxt = Get_Http(veryfy_url, 120000);
return responseTxt;
}
/// <summary>
/// 获取远程服务器ATN结果
/// </summary>
/// <param name="strUrl">指定URL路径地址</param>
/// <param name="timeout">超时时间设置</param>
/// <returns>服务器ATN结果</returns>
private string Get_Http(string strUrl, int timeout)
{
string strResult;
try
{
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(strUrl);
myReq.Timeout = timeout;
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream();
StreamReader sr = new StreamReader(myStream, Encoding.Default);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine());
}
strResult = strBuilder.ToString();
}
catch (Exception exp)
{
strResult = "错误:" + exp.Message;
}
return strResult;
}
}
}
\ No newline at end of file
This diff is collapsed.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Security.Cryptography;
namespace Mall.Common.Pay.Alipay
{
/// <summary>
/// 类名:MD5
/// 功能:MD5加密
/// 版本:3.3
/// 修改日期:2012-07-05
/// 说明:
/// 以下代码只是为了方便商户测试而提供的样例代码,商户可以根据自己网站的需要,按照技术文档编写,并非一定要使用该代码。
/// 该代码仅供学习和研究支付宝接口使用,只是提供一个参考。
/// </summary>
public sealed class AlipayMD5
{
/// <summary>
/// 构造函数
/// </summary>
public AlipayMD5()
{
}
/// <summary>
/// 签名字符串
/// </summary>
/// <param name="prestr">需要签名的字符串</param>
/// <param name="key">密钥</param>
/// <param name="_input_charset">编码格式</param>
/// <returns>签名结果</returns>
public static string Sign(string prestr, string key, string _input_charset)
{
StringBuilder sb = new StringBuilder(32);
prestr = prestr + key;
MD5 md5 = new MD5CryptoServiceProvider();
byte[] t = md5.ComputeHash(Encoding.GetEncoding(_input_charset).GetBytes(prestr));
for (int i = 0; i < t.Length; i++)
{
sb.Append(t[i].ToString("x").PadLeft(2, '0'));
}
return sb.ToString();
}
/// <summary>
/// 验证签名
/// </summary>
/// <param name="prestr">需要签名的字符串</param>
/// <param name="sign">签名结果</param>
/// <param name="key">密钥</param>
/// <param name="_input_charset">编码格式</param>
/// <returns>验证结果</returns>
public static bool Verify(string prestr, string sign, string key, string _input_charset)
{
string mysign = Sign(prestr, key, _input_charset);
if (mysign == sign)
{
return true;
}
else
{
return false;
}
}
}
}
\ No newline at end of file
This diff is collapsed.

using Mall.Common.Pay.WeChatPat.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
namespace Mall.Common.Pay.WeChatPat
{
/// <summary>
///
/// </summary>
public class HttpHelper
{
/// <summary>
/// 获取响应流
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public static Stream RequestStream(HttpParam param)
{
#region 处理地址栏参数
var getParamSb = new StringBuilder();
if (param.GetParam != null)
{
if (param.GetParam is string)
{
getParamSb.Append(param.GetParam.ToString());
}
else
{
param.GetParam.GetType().GetProperties().ToList().ForEach(d =>
{
getParamSb.AppendFormat("{0}={1}&", d.Name, d.GetValue(param.GetParam, null));
});
}
}
if (!string.IsNullOrWhiteSpace(getParamSb.ToString().TrimEnd('&')))
{
param.Url = string.Format("{0}?{1}", param.Url, getParamSb.ToString().TrimEnd('&'));
}
#endregion
var r = WebRequest.Create(param.Url) as HttpWebRequest;
if (!string.IsNullOrWhiteSpace(param.CertPath) && !string.IsNullOrWhiteSpace(param.CertPwd))
{
ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
var cer = new X509Certificate2(param.CertPath, param.CertPwd, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);
r.ClientCertificates.Add(cer);
#region 暂时不要的
//ServicePointManager.Expect100Continue = true;
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
//req.ProtocolVersion = HttpVersion.Version11;
//req.UserAgent = SUserAgent;
//req.KeepAlive = false;
//var cookieContainer = new CookieContainer();
//req.CookieContainer = cookieContainer;
//req.Timeout = 1000 * 60;
//req.Headers.Add("x-requested-with", "XMLHttpRequest");
#endregion
}
r.Timeout = param.TimeOut * 1000;
r.UserAgent = param.UserAgent;
r.Method = param.Method ?? "POST";
r.Referer = param.Referer;
r.CookieContainer = param.CookieContainer;
r.ContentType = param.ContentType;
if (param.PostParam != null)
{
var postParamString = "";
if (param.PostParam is string)
{
postParamString = param.PostParam.ToString();
}
else if (param.ParamType == HttpParamType.Form)
{
var dicParam = Common.Plugin.JsonHelper.DeserializeObject< Dictionary<string, string>>(Common.Plugin.JsonHelper.Serialize(param.PostParam));
postParamString = dicParam.Aggregate(postParamString, (current, dic) => current + (dic.Key + "=" + dic.Value + "&")).TrimEnd('&');
}
else
{
postParamString = Common.Plugin.JsonHelper.Serialize(param.PostParam);
}
var bs = param.Encoding.GetBytes(postParamString);
r.ContentLength = bs.Length;
using (var rs = r.GetRequestStream())
{
rs.Write(bs, 0, bs.Length);
}
}
return r.GetResponse().GetResponseStream();
}
/// <summary>
/// 获取请求参数
/// </summary>
/// <param name="param"></param>
public static string RequestString(HttpParam param)
{
var result = "";
using (var reader = new StreamReader(RequestStream(param), param.Encoding))
{
result = reader.ReadToEnd();
}
return result;
}
#region Get请求
/// <summary>
///
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public static string Get(HttpParam param)
{
param.Method = "GET";
return RequestString(param);
}
/// <summary>
/// 获取请求参数
/// </summary>
/// <typeparam name="T">泛型约束</typeparam>
/// <param name="url">地址</param>
/// <param name="getParam">参数</param>
/// <returns></returns>
public static T Get<T>(string url, object getParam)
{
var param = new HttpParam
{
Url = url,
Method = "GET",
GetParam = getParam
};
var str = Get(param);
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(str);
}
#endregion
#region Post 请求
/// <summary>
///
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public static string Post(HttpParam param)
{
param.Method = "POST";
var str = RequestString(param);
return str;
}
private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true;
}
#endregion
public static Encoding GetRequestEncoding(HttpRequest request)
{
var requestContentType = request.ContentType;
var requestMediaType = requestContentType == null ? default(MediaType) : new MediaType(requestContentType);
var requestEncoding = requestMediaType.Encoding;
if (requestEncoding == null)
{
requestEncoding = Encoding.UTF8;
}
return requestEncoding;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mall.Common.Pay.WeChatPat.Model
{
/// <summary>
/// 微信接口列表。
/// </summary>
public static class ApiList
{
#region 公众号接口
/// <summary>
/// 发送客服消息
/// </summary>
public static string MessageCustomSendUrl = "https://api.weixin.qq.com/cgi-bin/message/custom/send";
/// <summary>
/// 发送模板消息
/// </summary>
public static string MessageTemplateSendUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send";
/// <summary>
/// 获取access_token的接口地址
/// </summary>
public static string GetTokenUrl = "https://api.weixin.qq.com/cgi-bin/token";
/// <summary>
/// 获取jsapi_ticket的接口地址
/// </summary>
public static string GetticketUrl = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
/// <summary>
///
/// </summary>
public static string MenuCreateUrl = "https://api.weixin.qq.com/cgi-bin/menu/create";
/// <summary>
/// 查询菜单接口地址
/// </summary>
public static string MenuGetUrl = "https://api.weixin.qq.com/cgi-bin/menu/get";
/// <summary>
/// 删除菜单接口地址
/// </summary>
public static string MenuDeleteUrl = "https://api.weixin.qq.com/cgi-bin/menu/delete";
/// <summary>
///
/// </summary>
public static string MediaUploadUrl = "http://file.api.weixin.qq.com/cgi-bin/media/upload";
/// <summary>
///
/// </summary>
public static string MediaGet = "http://file.api.weixin.qq.com/cgi-bin/media/get";
/// <summary>
/// 网页授权获取用户信息
/// </summary>
public static string SnsUserInfo = "https://api.weixin.qq.com/sns/userinfo";
/// <summary>
/// 获取用户信息
/// </summary>
public static string GetUserInfo = "https://api.weixin.qq.com/cgi-bin/user/info";
/// <summary>
/// 需要 access_token
/// </summary>
public static string QrcodeCreateUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create";
/// <summary>
///
/// </summary>
public static string ShowQrcodeUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode";
/// <summary>
///
/// </summary>
public static string DownloadBillUrl = "https://api.mch.weixin.qq.com/pay/downloadbill";
/// <summary>
///
/// </summary>
public static string UnifiedOrderUrl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/// <summary>
///
/// </summary>
public static string GetOauth2AccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token";
/// <summary>
/// 获取永久素材的列表。地址栏需要access_token参数。
/// </summary>
public static string BatchgetMaterial = "https://api.weixin.qq.com/cgi-bin/material/batchget_material";
#endregion
#region 开放平台接口
/// <summary>
/// 该API用于获取第三方平台令牌(component_access_token)
/// </summary>
public static string ApiComponentToken = "https://api.weixin.qq.com/cgi-bin/component/api_component_token";
/// <summary>
/// 该API用于获取预授权码。预授权码用于公众号授权时的第三方平台方安全验证。地址栏需要component_access_token参数。
/// </summary>
public static string ApiCreatePreauthcode = "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode";
/// <summary>
/// 使用授权码换取公众号的接口调用凭据和授权信息。地址栏需要component_access_token参数。
/// </summary>
public static string ApiQueryAuth = "https://api.weixin.qq.com/cgi-bin/component/api_query_auth";
/// <summary>
/// 获取(刷新)授权公众号的接口调用凭据(令牌)。地址栏需要component_access_token参数。
/// </summary>
public static string ApiAuthorizerToken = "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token";
/// <summary>
/// 获取授权方的公众号帐号基本信息。该API用于获取授权方的公众号基本信息,包括头像、昵称、帐号类型、认证类型、微信号、原始ID和二维码图片URL。地址栏需要component_access_token参数。
/// </summary>
public static string ApiGetAuthorizerInfo = "https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info";
#endregion
}
}
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
namespace Mall.Common.Pay.WeChatPat.Model
{
/// <summary>
///
/// </summary>
//[Serializable]
[DataContract]
//[CollectionDataContractAttribute]
public class BaseResult : DynamicObject
{
/// <summary>
/// 构造函数
/// </summary>
public BaseResult()
{
this.IsSuccess = true;
this.Data = null;
this.Message = null;
}
/// <summary>
/// 构造函数
/// </summary>
/// <Param name="isSuccess"></Param>
public BaseResult(bool isSuccess)
{
this.IsSuccess = isSuccess;
this.Data = null;
this.Message = null;
}
/// <summary>
/// 构造函数
/// </summary>
/// <Param name="isSuccess"></Param>
/// <Param name="data"></Param>
public BaseResult(bool isSuccess, object data)
{
this.IsSuccess = isSuccess;
this.Data = data;
this.Message = null;
}
/// <summary>
/// 构造函数
/// </summary>
/// <Param name="isSuccess"></Param>
/// <Param name="data"></Param>
/// <Param name="message"></Param>
public BaseResult(bool isSuccess, object data, string message)
{
this.IsSuccess = isSuccess;
this.Data = data;
this.Message = message;
}
/// <summary>
/// 构造函数
/// </summary>
/// <Param name="isSuccess"></Param>
/// <Param name="data"></Param>
/// <Param name="message"></Param>
/// <Param name="dataCount"></Param>
public BaseResult(bool isSuccess, object data, string message, int dataCount)
{
this.IsSuccess = isSuccess;
this.Data = data;
this.Message = message;
this.DataCount = dataCount;
}
/// <summary>
/// 是否成功
/// </summary>
[DataMember]
public bool IsSuccess { get; set; }
/// <summary>
/// 错误信息
/// </summary>
[DataMember]
public string Message { get; set; }
/// <summary>
/// 返回数据
/// </summary>
[DataMember]
public object Data { get; set; }
/// <summary>
/// 数量数量
/// </summary>
[DataMember]
public int? DataCount { get; set; }
/// <summary>
/// 属性字典
/// </summary>
public Dictionary<string, object> Properties = new Dictionary<string, object>();
/// <summary>
/// 设置属性
/// </summary>
/// <param name="binder"></param>
/// <param name="value"></param>
/// <returns></returns>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
if (!Properties.Keys.Contains(binder.Name))
{
Properties.Add(binder.Name, value.ToString());
}
return true;
}
/// <summary>
/// 获取属性
/// </summary>
/// <param name="binder"></param>
/// <param name="result"></param>
/// <returns></returns>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return Properties.TryGetValue(binder.Name, out result);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mall.Common.Pay.WeChatPat.Model
{
/// <summary>
///
/// </summary>
public class HttpParam
{
/// <summary>
/// GET/POST
/// </summary>
public string Method { get; set; }
/// <summary>
///
/// </summary>
public string Url { get; set; }
/// <summary>
/// 参数类型。可选:Json、Form。默认Json。传入Form则会将new { Key1 = Value1, Key2 = Value2}转换成"key1=value1&key2=value2"形式。
/// </summary>
public HttpParamType ParamType { get; set; }
/// <summary>
/// Post参数。
/// <para>可以传入Json对像:new { Key1 = Value1, Key2 = Value2}</para>
/// <para>可以传入Json字符串:{"Key1":"Value1","Key2":"Value2"}</para>
/// <para>可以传入key/value字符串:"key1=value1&key2=value2"</para>
/// <para>可以传入xml字符串等等</para>
/// </summary>
public object PostParam { get; set; }
/// <summary>
/// Get参数
/// <para>可以传入Json对像:new { Key1 = Value1, Key2 = Value2}</para>
/// <para>可以传入Json字符串:{"Key1":"Value1","Key2":"Value2"}</para>
/// </summary>
public object GetParam { get; set; }
private int _timeOut = 10;
/// <summary>
/// 请求超时时间。单位:秒。默认值5秒。
/// </summary>
public int TimeOut
{
get { return _timeOut; }
set { _timeOut = value; }
}
private Encoding _encoding = Encoding.UTF8;
/// <summary>
///
/// </summary>
public Encoding Encoding
{
get { return _encoding; }
set { _encoding = value; }
}
/// <summary>
///
/// </summary>
public System.Net.CookieContainer CookieContainer { get; set; }
/// <summary>
///
/// </summary>
public string Referer { get; set; }
/// <summary>
///
/// </summary>
public string CertPath { get; set; }
/// <summary>
///
/// </summary>
public string CertPwd { get; set; }
private string _contentType = "application/x-www-form-urlencoded";
/// <summary>
///
/// </summary>
public string ContentType
{
get { return _contentType; }
set { _contentType = value; }
}
private string _userAgent = "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.1 (KHTML, like Gecko) Maxthon/4.1.2.4000 Chrome/26.0.1410.43 Safari/537.1";
/// <summary>
///
/// </summary>
public string UserAgent
{
get { return _userAgent; }
set { _userAgent = value; }
}
/// <summary>
///
/// </summary>
// public System.Web.HttpPostedFileBase PostedFile { get; set; }
}
/// <summary>
/// Http请求参数类型枚举
/// </summary>
public enum HttpParamType
{
/// <summary>
/// json数据。默认值。
/// </summary>
Json,
/// <summary>
/// 形如:key=value&key=value&key=value
/// </summary>
Form
}
}
using System;
namespace Mall.Common.Pay.WeChatPat.Model
{
/// <summary>
///
/// </summary>
//[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false)]
public sealed class JsonProp : Attribute
{
/// <summary>
/// Gets or sets the name of the property.
/// </summary>
/// <value>The name of the property.</value>
public string PropertyName { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="JsonProp"/> class.
/// </summary>
public JsonProp()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonProp"/> class with the specified name.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
public JsonProp(string propertyName)
{
PropertyName = propertyName;
}
}
}
\ No newline at end of file
using Mall.WeChat.Common;
namespace Mall.Common.Pay.WeChatPat.Model
{
/// <summary>
/// Token结果实体类
/// </summary>
public class TokenResult : WeChatResult
{
/// <summary>
/// 获取到的凭证
/// </summary>
public string access_token { get; set; }
/// <summary>
/// 凭证有效时间,单位:秒
/// </summary>
public int expires_in { get; set; }
}
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mall.Common.Pay.WeChatPat.Model
{
/// <summary>
///
/// </summary>
public class UserInfoResult
{
/// <summary>
/// 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
/// </summary>
[JsonProp(PropertyName = "subscribe")]
public string Subscribe { get; set; }
/// <summary>
/// 用户的标识,对当前公众号唯一
/// </summary>
[JsonProp(PropertyName = "openid")]
public string OpenId { get; set; }
/// <summary>
/// 用户的昵称
/// </summary>
[JsonProp(PropertyName = "nickname")]
public string NickName { get; set; }
/// <summary>
/// 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
/// </summary>
[JsonProp(PropertyName = "sex")]
public string Sex { get; set; }
/// <summary>
/// 用户所在城市
/// </summary>
[JsonProp(PropertyName = "city")]
public string City { get; set; }
/// <summary>
/// 用户所在国家
/// </summary>
[JsonProp(PropertyName = "country")]
public string Country { get; set; }
/// <summary>
/// 用户所在省份
/// </summary>
[JsonProp(PropertyName = "province")]
public string Province { get; set; }
/// <summary>
/// 用户的语言,简体中文为zh_CN
/// </summary>
[JsonProp(PropertyName = "language")]
public string Language { get; set; }
/// <summary>
/// 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
/// </summary>
[JsonProp(PropertyName = "headimgurl")]
public string HeadImgUrl { get; set; }
/// <summary>
///用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
/// </summary>
[JsonProp(PropertyName = "subscribe_time")]
public string SubscribeTime { get; set; }
/// <summary>
///只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
/// </summary>
[JsonProp(PropertyName = "unionid")]
public string UnionId { get; set; }
/// <summary>
///错误时微信会返回错误码等信息
/// </summary>
[JsonProp(PropertyName = "errcode")]
public string Errcode { get; set; }
/// <summary>
///错误时微信会返回错误码等信息
/// </summary>
[JsonProp(PropertyName = "errmsg")]
public string ErrMsg { get; set; }
}
}
using System;
using Mall.Common;
using Newtonsoft.Json;
namespace Mall.WeChat.Common
{
/// <summary>
/// 微信配置实体类
/// </summary>
public class WeChatSetting
{
#region 公众号设置
/// <summary>
/// 公众号名称
/// </summary>
public string sAccountName { get; set; }
/// <summary>
/// 微信原始ID
/// </summary>
public string sAccountID { get; set; }
/// <summary>
/// 微信绑定Token
/// </summary>
public string sToken { get; set; }
/// <summary>
/// 微信开发者绑定Url地址
/// </summary>
public string sUrl { get; set; }
/// <summary>
/// AppId(应用ID)
/// </summary>
public string sAppId { get; set; }
/// <summary>
/// sAppSecret(应用密钥)
/// </summary>
public string sAppSecret { get; set; }
/// <summary>
/// 商户号
/// </summary>
public string sMchId { get; set; }
/// <summary>
/// API秘钥
/// </summary>
public string sPaySignKey { get; set; }
/// <summary>
/// 微信支付回调地址
/// </summary>
public string sTenpayNotify { get; set; }
/// <summary>
/// 微信支付发起支付地址
/// </summary>
public string sSendUrl { get; set; }
/// <summary>
///
/// </summary>
public string sCertPath { get; set; }
/// <summary>
///
/// </summary>
public string sCertPwd { get; set; }
#endregion
#region 开放平台设置
/// <summary>
///
/// </summary>
public string sOpenName { get; set; }
/// <summary>
/// APPkey
/// </summary>
public string sOpenAppID { get; set; }
/// <summary>
/// APP密钥
/// </summary>
public string sOpenAppSecret { get; set; }
/// <summary>
/// 商户号
/// </summary>
public string sOpenMchID { get; set; }
/// <summary>
/// API密钥
/// </summary>
public string sOpenKey { get; set; }
/// <summary>
///
/// </summary>
public string sOpenCertPath { get; set; }
/// <summary>
///
/// </summary>
public string sOpenCertPwd { get; set; }
#endregion
}
/// <summary>
/// 通用配置,可以修改为其它方式存储这些配置。
/// </summary>
public class WeChatConfig
{
/// <summary>
/// 微信配置
/// </summary>
public static WeChatSetting Setting { get; set; }
/// <summary>
/// 初始化配置
/// </summary>
public static void InitConfig()
{
try
{
string confirmingStr = Config.APPPay;
Setting = JsonConvert.DeserializeObject<WeChatSetting>(confirmingStr);
}
catch(Exception ex)
{
throw ex;
}
}
#region 公众号配置
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetAppId()
{
if (Setting == null)
InitConfig();
return Setting.sAppId;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetMchId()
{
if (Setting == null)
InitConfig();
return Setting.sMchId;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetKey()
{
if (Setting == null)
InitConfig();
return Setting.sPaySignKey;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetCertPath()
{
if (Setting == null)
InitConfig();
return Setting.sCertPath;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetCertPwd()
{
if (Setting == null)
InitConfig();
return Setting.sCertPwd;
}
/// <summary>
/// 获取web.config的WeChatSecret
/// </summary>
/// <returns></returns>
public static string GetSecret()
{
if (Setting == null)
InitConfig();
return Setting.sAppSecret;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetNotify()
{
if (Setting == null)
InitConfig();
return Setting.sTenpayNotify;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetToken()
{
if (Setting == null)
InitConfig();
return Setting.sToken;
}
#endregion
#region 第三方开放平台配置
/// <summary>
/// 获取OpenAppId
/// </summary>
/// <returns></returns>
public static string GetOpenAppId()
{
if (Setting == null)
InitConfig();
return Setting.sOpenAppID;
}
/// <summary>
/// 获取OpenMchID
/// </summary>
/// <returns></returns>
public static string GetOpenMchID()
{
if (Setting == null)
InitConfig();
return Setting.sOpenMchID;
//return WebConfigurationManager.AppSettings["OpenAppSecret"];
}
/// <summary>
/// 获取OpenKey
/// </summary>
/// <returns></returns>
public static string GetOpenKey()
{
if (Setting == null)
InitConfig();
return Setting.sOpenKey;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetOpenToken()
{
return WebConfigurationManager.AppSettings["OpenToken"];
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetOpenDesKey()
{
return WebConfigurationManager.AppSettings["OpenDESKey"];
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetOpenCertPath()
{
if (Setting == null)
InitConfig();
return Setting.sOpenCertPath;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public static string GetOpenCertPwd()
{
if (Setting == null)
InitConfig();
return Setting.sOpenCertPwd;
}
#endregion
}
}

using Mall.Common.Pay.WeChatPat.Model;
namespace Mall.WeChat.Common
{
/// <summary>
/// 微信结果码
/// </summary>
public class WeChatResult
{
/// <summary>
///
/// </summary>
public WeChatResult()
{
}
/// <summary>
/// ErrCode传入0表示成功
/// </summary>
public WeChatResult(int errCode)
{
_errCode = errCode;
}
/// <summary>
/// ErrCode传入0表示成功
/// </summary>
public WeChatResult(int errCode, string errMsg)
{
_errMsg = errMsg;
_errCode = errCode;
}
/// <summary>
///
/// </summary>
private int _errCode;
/// <summary>
/// 结果码
/// </summary>
[JsonProp(PropertyName = "errcode")]
public int ErrCode
{
get { return _errCode; }
set { _errCode = value; }
}
/// <summary>
///
/// </summary>
private string _errMsg;
/// <summary>
/// 结果文本说明
/// </summary>
[JsonProp(PropertyName = "errmsg")]
public string ErrMsg
{
get { return _errMsg; }
set
{
switch (ErrCode)
{
case -1:
_errMsg = ErrCode + "系统繁忙,请稍候再试_" + value;
break;
case 61003:
_errMsg = ErrCode + "该公众号已取消授权_" + value;
break;
default:
if (ErrCode == 0)
_errMsg = value;
else
_errMsg = ErrCode + value;
break;
}
}
}
private bool? _isSuccess;
/// <summary>
/// 是否成功
/// </summary>
public bool IsSuccess
{
get
{
if (_isSuccess == null)
{
return ErrCode == 0;
}
return _isSuccess.Value;
}
set { _isSuccess = value; }
}
}
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mall.Common.Pay.WeChatPat
{
/// <summary>
/// 支付参数实体
/// </summary>
public class PayParam : WeChatParam
{
/// <summary>
/// 订单号
/// </summary>
public string OrderNumber { get; set; }
/// <summary>
/// 退款订单号
/// </summary>
public string RefundNumber { get; set; }
/// <summary>
/// 金额(分)
/// </summary>
public int? TotalFee { get; set; }
/// <summary>
/// 退款金额
/// </summary>
public int? RefundFee { get; set; }
/// <summary>
/// 过期时间,格式(20141010121314)
/// </summary>
public string TimeExpire { get; set; }
/// <summary>
/// 商品名称
/// </summary>
public string ProductName { get; set; }
/// <summary>
/// 支付成功回调地址
/// </summary>
public string NotifyUrl { get; set; }
/// <summary>
/// 支付方式
/// </summary>
public TradeType? TradeType { get; set; }
/// <summary>
/// 是否充值订单
/// </summary>
public bool IsRecharge { get; set; }
/// <summary>
/// 小程序id
/// </summary>
public int MallBaseId { get; set; }
/// <summary>
/// 商户ID
/// </summary>
public int TenantId { get; set; }
}
/// <summary>
/// 支付方式
/// </summary>
public enum TradeType
{
/// <summary>
/// JSAPI
/// </summary>
JSAPI,
/// <summary>
/// NATIVE
/// </summary>
NATIVE,
/// <summary>
/// APP
/// </summary>
APP
}
}

using Microsoft.AspNetCore.Http;
using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
namespace Mall.Common.Pay.WeChatPat
{
/// <summary>
/// 微信请求处理类
/// </summary>
public class RequestHandler
{
private IHttpContextAccessor _accessor;
public RequestHandler(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
/// <summary>
/// 请求的参数
/// </summary>
protected Hashtable Parameters;
/// <summary>
/// 密钥
/// </summary>
private string _key;
/// <summary>
/// debug信息
/// </summary>
private string _debugInfo;
/// <summary>
/// 构造函数
/// </summary>
public RequestHandler()
{
this._debugInfo = "";
Parameters = new Hashtable();
}
/// <summary>
/// 初始化函数
/// </summary>
public virtual void Init()
{
}
/// <summary>
/// 获取debug信息
/// </summary>
/// <returns></returns>
public String GetDebugInfo()
{
return _debugInfo;
}
/// <summary>
/// 获取密钥
/// </summary>
/// <returns></returns>
public string GetKey()
{
return _key;
}
/// <summary>
/// 设置密钥
/// </summary>
/// <param name="key"></param>
public void SetKey(string key)
{
this._key = key;
}
/// <summary>
/// 设置参数值
/// </summary>
/// <param name="parameter"></param>
/// <param name="parameterValue"></param>
public void SetParameter(string parameter, string parameterValue)
{
if (!string.IsNullOrEmpty(parameter))
{
if (Parameters.Contains(parameter))
{
Parameters.Remove(parameter);
}
Parameters.Add(parameter, parameterValue);
}
}
/// <summary>
/// 获取package带参数的签名包
/// </summary>
/// <returns></returns>
public string GetRequestURL()
{
this.CreateMd5Sign();
var sb = new StringBuilder();
var akeys = new ArrayList(Parameters.Keys);
akeys.Sort();
foreach (string k in akeys)
{
var v = (string)Parameters[k];
if (null != v && String.Compare("key", k, StringComparison.Ordinal) != 0)
{
sb.Append(k + "=" + UrlEncode(v, GetCharset()) + "&");
}
}
//去掉最后一个&
if (sb.Length > 0)
{
sb.Remove(sb.Length - 1, 1);
}
return sb.ToString();
}
/// <summary>
/// 对字符串进行URL编码
/// </summary>
/// <param name="instr"></param>
/// <param name="charset">默认值:utf-8</param>
/// <returns></returns>
public static string UrlEncode(string instr, string charset)
{
if (instr == null || instr.Trim() == "")
return "";
var res = HttpUtility.UrlEncode(instr, !string.IsNullOrWhiteSpace(charset)
? Encoding.GetEncoding(charset)
: Encoding.GetEncoding("utf-8"));
return res;
}
/// <summary>
/// 创建package签名,按参数名称a-z排序,遇到空值的参数不参加签名。
/// </summary>
/// <returns></returns>
public string CreateMd5Sign()
{
var sb = new StringBuilder();
var akeys = new ArrayList(Parameters.Keys);
akeys.Sort();
foreach (string k in akeys)
{
var v = (string)Parameters[k];
if (null != v && String.Compare("", v, StringComparison.Ordinal) != 0
&& String.Compare("sign", k, StringComparison.Ordinal) != 0 && String.Compare("key", k, StringComparison.Ordinal) != 0)
{
sb.Append(k + "=" + v + "&");
}
}
sb.Append("key=" + GetKey());
var sign = Plugin.SecurityHelper.MD5EncryptWeChat(sb.ToString(), GetCharset()).ToUpper();
return sign;
}
/// <summary>
/// 创建sha1签名
/// </summary>
/// <returns></returns>
public string CreateSHA1Sign()
{
var sb = new StringBuilder();
var akeys = new ArrayList(Parameters.Keys);
akeys.Sort();
foreach (string k in akeys)
{
var v = (string)Parameters[k];
if (null != v && String.Compare("", v, StringComparison.Ordinal) != 0
&& String.Compare("sign", k, StringComparison.Ordinal) != 0 && String.Compare("key", k, StringComparison.Ordinal) != 0)
{
if (sb.Length == 0)
{
sb.Append(k + "=" + v);
}
else
{
sb.Append("&" + k + "=" + v);
}
}
}
var paySign = Sha1Util.GetSha1(sb.ToString()).ToLower();
return paySign;
}
/// <summary>
/// 输出XML
/// </summary>
/// <returns></returns>
public string ParseXml()
{
var sb = new StringBuilder();
sb.Append("<xml>");
foreach (string k in Parameters.Keys)
{
var v = (string)Parameters[k];
if (Regex.IsMatch(v, @"^[0-9.]$"))
{
sb.Append("<" + k + ">" + v + "</" + k + ">");
}
else
{
sb.Append("<" + k + "><![CDATA[" + v + "]]></" + k + ">");
}
}
sb.Append("</xml>");
return sb.ToString();
}
/// <summary>
/// 输出XML
/// </summary>
/// <returns></returns>
public string ParseXmlNoCdata()
{
var sb = new StringBuilder();
sb.Append("<xml>");
foreach (string k in Parameters.Keys)
{
var v = (string)Parameters[k];
sb.Append("<" + k + ">" + v + "</" + k + ">");
}
sb.Append("</xml>");
return sb.ToString();
}
/// <summary>
/// 输出JSON
/// </summary>
/// <returns></returns>
public string ParseJson()
{
var sb = new StringBuilder();
sb.Append("{");
foreach (string k in Parameters.Keys)
{
var v = (string)Parameters[k];
sb.Append("\"" + k + "\":\"" + v + "\",");
}
var str = sb.ToString().TrimEnd(',');
str += "}";
return str;
}
/// <summary>
/// 获取所有参数
/// </summary>
/// <returns></returns>
public Hashtable GetAllParameters()
{
return this.Parameters;
}
/// <summary>
/// 获取编号
/// </summary>
/// <returns></returns>
protected virtual string GetCharset()
{
//return "UTF-8";
try
{
return HttpHelper.GetRequestEncoding(_accessor.HttpContext.Request).BodyName; // HttpContext.Current.Request.ContentEncoding.BodyName;
}
catch (Exception)
{
return "UTF-8";
}
}
}
}
using Microsoft.AspNetCore.Http;
using System;
using System.Collections;
using System.Text;
using System.Xml;
namespace Mall.Common.Pay.WeChatPat
{
/// <summary>
/// 微信支付响应类
/// </summary>
public class ResponseHandler
{
private IHttpContextAccessor _accessor;
public ResponseHandler(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
/// <summary>
/// 密钥
/// </summary>
private string _key;
/// <summary>
/// 微信服务器编码方式
/// </summary>
private const string Charset = "utf-8";
/// <summary>
///
/// </summary>
private Hashtable xmlMap;
/// <summary>
/// 获取页面提交的get和post参数
/// </summary>
public ResponseHandler()
{
xmlMap = new Hashtable();
if (_accessor.HttpContext.Request.ContentLength > 0)
{
var reader = new System.IO.StreamReader(_accessor.HttpContext.Request.Body, Encoding.UTF8);
_accessor.HttpContext.Request.Body.Position = 0;
var xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
var root = xmlDoc.SelectSingleNode("xml");
var xnl = root.ChildNodes;
foreach (XmlNode xnf in xnl)
{
xmlMap.Add(xnf.Name, xnf.InnerText);
}
}
//if (HttpContext.Current.Request.InputStream.Length > 0)
//{
// var xmlDoc = new XmlDocument();
// xmlDoc.Load(HttpContext.Current.Request.InputStream);
// var root = xmlDoc.SelectSingleNode("xml");
// var xnl = root.ChildNodes;
// foreach (XmlNode xnf in xnl)
// {
// xmlMap.Add(xnf.Name, xnf.InnerText);
// }
//}
}
/// <summary>
/// 初始化加载
/// </summary>
public virtual void Init()
{
}
/// <summary>
/// 获取密钥
/// </summary>
/// <returns></returns>
public string GetKey()
{
return _key;
}
/// <summary>
/// 设置密钥
/// </summary>
/// <param name="key"></param>
public void SetKey(string key)
{
this._key = key;
}
/// <summary>
/// 获取参数值
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public string GetParameter(string parameter)
{
var s = (string)xmlMap[parameter];
return s ?? "";
}
/// <summary>
/// 设置参数值
/// </summary>
/// <param name="parameter"></param>
/// <param name="parameterValue"></param>
public void SetParameter(string parameter, string parameterValue)
{
//if (parameter != null && parameter != "")
//{
// if (parameters.Contains(parameter))
// {
// parameters.Remove(parameter);
// }
// parameters.Add(parameter, parameterValue);
//}
}
/// <summary>
/// 判断微信签名
/// </summary>
/// <returns></returns>
public virtual bool IsWXsign(out string error)
{
var sb = new StringBuilder();
var signMap = new Hashtable();
foreach (string k in xmlMap.Keys)
{
if (k != "sign")
{
signMap.Add(k.ToLower(), xmlMap[k]);
}
}
var akeys = new ArrayList(signMap.Keys);
akeys.Sort();
foreach (string k in akeys)
{
var v = (string)signMap[k];
sb.Append(k + "=" + v + "&");
}
sb.Append("key=" + this._key);
var sign = Plugin.SecurityHelper.MD5EncryptWeChat(sb.ToString(), Charset).ToUpper();
error = "sign = " + sign + "\r\n xmlMap[sign]=" + xmlMap["sign"].ToString();
return sign.Equals(xmlMap["sign"]);
}
/// <summary>
/// 获取编码方式
/// </summary>
/// <returns></returns>
protected virtual string GetCharset()
{
//return "UTF-8";
try
{
return HttpHelper.GetRequestEncoding(_accessor.HttpContext.Request).BodyName;
}
catch (Exception)
{
return "UTF-8";
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace Mall.Common.Pay.WeChatPat
{
/// <summary>
/// 签名帮助类
/// </summary>
public class Sha1Util
{
/// <summary>
/// 获取sha1签名
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static String GetSha1(String str)
{
//建立SHA1对象
SHA1 sha = new SHA1CryptoServiceProvider();
//将mystr转换成byte[]
var enc = new ASCIIEncoding();
var dataToHash = enc.GetBytes(str);
//Hash运算
var dataHashed = sha.ComputeHash(dataToHash);
//将运算结果转换成string
var hash = BitConverter.ToString(dataHashed).Replace("-", "");
return hash;
}
}
}
using Mall.WeChat.Common;
using Mall.Common.Pay.WeChatPat.Model;
using System;
namespace Mall.Common.Pay.WeChatPat
{
/// <summary>
/// Token帮助类
/// </summary>
public class TokenHelper
{
/// <summary>
/// 缓存实例对象
/// </summary>
// private static Cache.ICache cache = Cache.MemcacheFactory.GetMenchageClient(Config.GetAppSetting("MemcachedKeyPoolName"));
/// <summary>
/// 获取access_token。会缓存,过期后自动重新获取新的token。
/// </summary>
public static TokenResult GetAccessToken()
{
//var appId = WeChatConfig.GetAppId();
//var secret = WeChatConfig.GetSecret();
var result = new TokenResult();
//if (cache.Exists("AccessToken" + appId))
//{
// result = (TokenResult)cache.Get("AccessToken" + appId);
//}
//if (result == null || string.IsNullOrWhiteSpace(result.access_token))
//{
// result = HttpHelper.Get<TokenResult>(ApiList.GetTokenUrl, new
// {
// grant_type = "client_credential",
// appid = appId,
// secret = secret
// });
// if (result.IsSuccess)
// {
// cache.Set("AccessToken" + appId, result, result.expires_in - 60);
// }
// else
// {
// Plugin.LogHelper.Write(null,"GetAccessToken失败!" + result.ErrMsg);
// }
//}
return result;
}
}
}
using Mall.Common.Pay.WeChatPat.Model;
using Mall.WeChat.Common;
using System.Collections.Generic;
namespace Mall.Common.Pay.WeChatPat
{
/// <summary>
/// 微信帮助类
/// </summary>
public class WeChatHelper
{
/// <summary>
/// 根据Code获取openid失败
/// </summary>
/// <param name="sCode"></param>
/// <returns></returns>
public static UserInfoResult GetUserInfoByCode(string sCode)
{
var dic = GetOauth2AccessToken(sCode);
if (dic.ContainsKey("openid"))
{
var result = HttpHelper.Get<UserInfoResult>(ApiList.GetUserInfo, new
{
access_token = TokenHelper.GetAccessToken().access_token,
openid = dic["openid"],
lang = "zh_CN"
});
return result;
}
Plugin.LogHelper.Write(null, "GetUserInfoByCode");
return null;
}
/// <summary>
/// 根据Code获取用户授权信息
/// </summary>
/// <param name="sCode"></param>
/// <returns></returns>
public static Dictionary<string, string> GetOauth2AccessToken(string sCode)
{
var param2 = new
{
appid = "", //WeChatConfig.GetAppId(),
secret = "",// WeChatConfig.GetSecret(),
code = sCode,
grant_type = "authorization_code"
};
var dic = HttpHelper.Get<Dictionary<string, string>>(ApiList.GetOauth2AccessTokenUrl, param2);
return dic;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mall.Common.Pay.WeChatPat
{
/// <summary>
/// 微信支付参数实体
/// </summary>
public class WeChatParam
{
/// <summary>
/// 微信接入方式
/// </summary>
public WeChatType WeChatType { get; set; }
#region 常用
/// <summary>
/// 微信OpenId
/// </summary>
public string OpenId { get; set; }
/// <summary>
/// UUID
/// </summary>
public string Unionid { get; set; }
/// <summary>
/// Token
/// </summary>
public string AccessToken { get; set; }
/// <summary>
///
/// </summary>
public string WeChatPublic { get; set; }
/// <summary>
///
/// </summary>
public bool Debug { get; set; }
/// <summary>
///
/// </summary>
public string Url { get; set; }
/// <summary>
///
/// </summary>
public string Content { get; set; }
/// <summary>
///
/// </summary>
public string Code { get; set; }
#endregion
}
/// <summary>
/// 微信接入方式
/// </summary>
public enum WeChatType
{
/// <summary>
/// 公众号
/// </summary>
Public = 1,
/// <summary>
/// 开放平台
/// </summary>
Open = 2
}
}
This diff is collapsed.
......@@ -13,20 +13,20 @@ namespace Mall.Common.Plugin
/// </summary>
public class IPHelper
{
/// <summary>
/// 获取真实IP地址
/// </summary>
/// <returns></returns>
///// <summary>
///// 获取真实IP地址
///// </summary>
///// <returns></returns>
//public static string GetClientIP()
//{
// return GetClientIP(HttpContext.Current);
//}
/// <summary>
/// 获取客户端IP地址
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
///// <summary>
///// 获取客户端IP地址
///// </summary>
///// <param name="context"></param>
///// <returns></returns>
//private static string GetClientIP(HttpContext context)
//{
// string text = string.Empty;
......
......@@ -176,6 +176,18 @@ namespace Mall.Model.Entity.User
set;
}
/// <summary>
/// 微信支付证书路径 Add By:W 2020.05.26
/// </summary>
public string WeChatPayCertificateUrl
{
get;
set;
}
/// <summary>
/// 下单成功提醒(类目:服装/鞋/箱包)
/// </summary>
......
This diff is collapsed.
-----BEGIN CERTIFICATE-----
MIID6TCCAtGgAwIBAgIUT60pj0AQhQ54pRkLuCpmAT3Paa4wDQYJKoZIhvcNAQEL
BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT
FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg
Q0EwHhcNMTkxMTExMDI0MTM3WhcNMjQxMTA5MDI0MTM3WjB7MRMwEQYDVQQDDAox
NTYyMjc3OTQxMRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xJzAlBgNVBAsM
HuaIkOmDveW+rumAlOenkeaKgOaciemZkOWFrOWPuDELMAkGA1UEBgwCQ04xETAP
BgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
6DHoGyItQITtrw8XVw/Ou6L/TOYPS8QnQG3xFqoeQYB0CINgsH2dwsTot03bJ+0k
R0LdRXPy78I2VEKk+L4t1dYifxB7esH9NjPVwKUynUU9nlu5vZdS0bzJX2Vv1dPm
yElBz/Eui7hRQ/sH6c+DzYiZGFrndnp2Qiw0HnpeFUKfJMNyyNIfNfD6jbjLsay8
ziBgw6yDn75TvT0VdbRAlX+8Amsf+NIsF6qDYfnb+cOIat3AWYZ/+nU1VdTyajEh
ukffPl/L5lnzP+QcrcFD7sYoGtI80OgoNo4/HSkpyfe1hK7D71Y3d7L3ocLdV0Cd
CQqp07H+Y4M5xyJs0YvHiQIDAQABo4GBMH8wCQYDVR0TBAIwADALBgNVHQ8EBAMC
BPAwZQYDVR0fBF4wXDBaoFigVoZUaHR0cDovL2V2Y2EuaXRydXMuY29tLmNuL3B1
YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRCMDZBRDM5NzU0OTg0NkMw
MUMzRThFQkQyMA0GCSqGSIb3DQEBCwUAA4IBAQAF9daTjvIikm89wGwtOYkRHtVd
zqAX11w9X3g11sylQ8+qxveISFbzikM/FNzrcliu5pMll5fh8jRKTEz0Bk5erPhJ
yLJeOzNpz454PeQ1Oqdr8jlfIeygcqXt+Td4ceNRxA8ApfvbYEc+vI+5NWdSyH6T
/bPLwsgYibINKjuwikJ0DNF+lXEYpL53inCj5fGmbwah3Sb62StpAPHTDm+aEHsW
j4i0uuG58PhszKL4ycpJbAdgAEmy2nqHQQYdoE59SGSuTLATWLl9diz6SLgUei+V
rVvTUhNXS0GKNqZO6/nntE/+jGIiF1Hs+bNMQc5OCL6oL3QSf4unXjZA9r0b
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDoMegbIi1AhO2v
DxdXD867ov9M5g9LxCdAbfEWqh5BgHQIg2CwfZ3CxOi3Tdsn7SRHQt1Fc/LvwjZU
QqT4vi3V1iJ/EHt6wf02M9XApTKdRT2eW7m9l1LRvMlfZW/V0+bISUHP8S6LuFFD
+wfpz4PNiJkYWud2enZCLDQeel4VQp8kw3LI0h818PqNuMuxrLzOIGDDrIOfvlO9
PRV1tECVf7wCax/40iwXqoNh+dv5w4hq3cBZhn/6dTVV1PJqMSG6R98+X8vmWfM/
5BytwUPuxiga0jzQ6Cg2jj8dKSnJ97WErsPvVjd3svehwt1XQJ0JCqnTsf5jgznH
ImzRi8eJAgMBAAECggEASoeaZPs3YzpHwKUrbLqaNQhAwkImLr+ribbAZ/H6/DNr
C0CATKZFeTsTJ6NJ8SrhNi50L9Lj66l/HtS1d1I0DCtLr1VvDRwvVrKUrd1Yvbp3
6NiwafakksXyLTi2CQCXVzqMcV6M/jQPga6V/6qoN9Tcr0Cegx0T0HG32QCWKmQ3
ba4YvVcu9KqE7YESj95EHSmy51Yf2D0KT8YNrcQKv3Ls11iwiv3IxvAGd6UTAEfq
UxAwDi5PWs3pAxtwMHpuigre0uj0BK3fWO5qGqUmRzxNUzIHdjGqM8On/NSOl7X0
qT0ffnaHYVl+oNsRF58bvZOX5Vge8Fbv2NPmY6BzsQKBgQD8OEIgeFLkowH2D1Zb
eAU1OdByNcLVvP2o+3ezbreFQNFDZHacjaKY3PqpF/3W8b0PLq34A/ij9bvK2zgU
UlXAnA/2TAMQUwuoPLwvRloseeaPxfMbbZiFFrhft5oyyEtxdPbzrEqEvNdyuU22
+Yq0EtEEUbRp9XN0rJtmH1HpOwKBgQDrrNCvyK9eQdFBcFc91OFDMWyaR4LhW9qU
4/BZK4YYmtsCJ5ljfVCIgt4IDP7083KOhSAFfoM6lk5fzlWP6qbFGQqUa1S2vINz
FtlrtixsP+20eUp7lh4gW0xC/KZWab2juXAmYQ5BdOVaPLMLj2iqQXEGUVxN/JG9
OHfAKrgmCwKBgQDC9yoGt3w8SNVnQ4vZwPkln79FydEGL8VVLq3lAhzS4LvigHI/
qiyaRZdtxqHt2YfviIHqSgeVlorH0JWU/+BRt1GPbkqf/9HvBqPhV1y1LLXRRY8b
EKjpmBqFwwNrZfELjwKmcfRYjzFr+VndqyBQ+oqf8BiqH5ZUBmlJk8RZqQKBgQCQ
n288wAFl7SvVZXQT/IPzsOu9TS7yzmQ3RB1lCwFyLe1ByD0nwWnfK7fG5vq6JH7j
GKyK0pUDKeOUhVEaTNvkTbahV7AXp11fDeGEaLmgACcFvfzIFFoObxhAbzxAAQmf
5Bb/ZkXSQ0LPejpBWNLYz+nk/56OOPTSUkmiQlTY+wKBgQDQKVtp6/PiyndkcjEP
nZbY3KF0nZsgaexGHOcd+qOvzHa9paEsdvd3CdYAoYvj30CwnZCYTHfnTp36/jvP
Q4JmQMzuX/eht8qU+2HnEqyeN4J2Hm/VRiAZ/Fg4w2YXSEXGnre1GvT2fq4qs1Jt
k29wkMW05u2FK917djbMY7NTIw==
-----END PRIVATE KEY-----
欢迎使用微信支付!
附件中的三份文件(证书pkcs12格式、证书pem格式、证书密钥pem格式),为接口中强制要求时需携带的证书文件。
证书属于敏感信息,请妥善保管不要泄露和被他人复制。
不同开发语言下的证书格式不同,以下为说明指引:
证书pkcs12格式(apiclient_cert.p12)
包含了私钥信息的证书文件,为p12(pfx)格式,由微信支付签发给您用来标识和界定您的身份
部分安全性要求较高的API需要使用该证书来确认您的调用身份
windows上可以直接双击导入系统,导入过程中会提示输入证书密码,证书密码默认为您的商户号(如:1900006031)
证书pem格式(apiclient_cert.pem)
从apiclient_cert.p12中导出证书部分的文件,为pem格式,请妥善保管不要泄漏和被他人复制
部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供
您也可以使用openssl命令来自己导出:openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem
证书密钥pem格式(apiclient_key.pem)
从apiclient_cert.p12中导出密钥部分的文件,为pem格式
部分开发语言和环境,不能直接使用p12文件,而需要使用pem,所以为了方便您使用,已为您直接提供
您也可以使用openssl命令来自己导出:openssl pkcs12 -nocerts -in apiclient_cert.p12 -out apiclient_key.pem
备注说明:
由于绝大部分操作系统已内置了微信支付服务器证书的根CA证书, 2018年3月6日后, 不再提供CA证书文件(rootca.pem)下载
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using Mall.Common.API;
using Mall.Common.Pay.WeChatPat;
using Mall.Common.Plugin;
using Mall.WebApi.Filter;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
namespace Mall.WebApi.Controllers.AppletWeChat
{
[Route("api/[controller]/[action]")]
[ApiExceptionFilter]
[ApiController]
[EnableCors("AllowCors")]
public class WeChatNotifyController : BaseController
{
private static object _lock = new object();
/// <summary>
/// 微信支付方法
/// </summary>
/// <param name="sOrderNo"></param>
/// <param name="sCurOpenID"></param>
/// <returns></returns>
[HttpGet]
[HttpPost]
public ApiResult DoPay(string sOrderNo, string sCurOpenID = "")
{
if (string.IsNullOrWhiteSpace(sCurOpenID))
{
return ApiResult.Failed("OpenId不能为空!");
}
string result = "";
//判断订单信息
//var model = new REBORN.Module.SellModule.CounponOrderModule().GetEntity(Convert.ToInt32(sOrderNo));
//if (model == null)
//{
// return ApiResult.Failed("订单信息不存在!");
//}
//if (model.OrderState == 2)
//{
// return ApiResult.Failed("订单已支付");
//}
//if (model.OrderState == 3)
//{
// return ApiResult.Failed("订单已取消");
//}
var payParam = new Common.Pay.WeChatPat.PayParam()
{
TotalFee = 1,// Convert.ToInt32(model.PreferPrice * 100),//总价,单位:分。2500即25元
OpenId = sCurOpenID,//支付用户的OpenId
OrderNumber = (System.DateTime.Now.ToString("yyyyMMddHHmmssfff")) + sOrderNo,
ProductName = "测试商品名称", //model.ProductName,
IsRecharge = false
};
try
{
LogHelper.Write(null, "DoPay-H5:" + payParam);
App_Code.PayUtil PayUtil = new App_Code.PayUtil();
result = PayUtil.CreateJSAPIPayJson(payParam);
return ApiResult.Success("", result);
}
catch (Exception ex)
{
if (ex.Message.Contains("timed out"))
{
App_Code.PayUtil PayUtil = new App_Code.PayUtil();
var json = PayUtil.CreateJSAPIPayJson(payParam);
return ApiResult.Success("", json);
}
}
return ApiResult.Success();
}
/// <summary>
///
/// </summary>
/// <returns></returns>
[HttpGet]
[HttpPost]
public string Notify()
{
var req = new RequestHandler();
App_Code.PayUtil PayUtil = new App_Code.PayUtil();
var result = PayUtil.Notify();
if (result.IsSuccess)
{
var dic = ((Dictionary<string, string>)result.Data);
//订单No:dic["sOrderNo"]
//支付金额:dic["dPrice"]
//开始回写订单状态
lock (_lock)
{
string sOrderNo = dic["sOrderNo"];
sOrderNo = sOrderNo.Substring(17, 5);
// var model = new REBORN.Module.SellModule.CounponOrderModule().GetEntity(Convert.ToInt32(sOrderNo));//获取订单信息
decimal dPaid = Convert.ToDecimal(dic["dPrice"]) / 100;
string sTradeNo = dic["sTradeNo"];
string sPayerOpenID = dic["sPayerOpenID"];
//处理订单信息2020-05-26 逻辑还未处理
#region 处理订单信息
//if (model.PreferPrice == dPaid)
//{
// model.PayType = dic["OrderPayType"].Equals("JSAPI", StringComparison.CurrentCultureIgnoreCase) ? 1 : 2;
// model.sTradeNo = sTradeNo;
// model.sPayerOpenID = sPayerOpenID;
// model.Income = dPaid;
// //查询订单信息
// try
// {
// }
// catch (Exception ex)
// {
// Common.Plugin.LogHelper.Write(ex, string.Format("Notify:infoError"));
// }
// req.SetParameter("return_code", "SUCCESS");
// req.SetParameter("return_msg", "OK");
//}
//else
//{
// req.SetParameter("return_code", "FAIL");
// req.SetParameter("return_msg", "支付金额与订单金额不等");
//}
#endregion
}
var reqXml = req.ParseXml();
//告诉微信我们已经处理成功,不需要再调用我们的接口了
return reqXml;
}
else
{
req.SetParameter("return_code", "FAIL");
req.SetParameter("return_msg", "订单失败");
var reqXmlFAIL = req.ParseXml();
LogHelper.Write(null, "Notify返回信息:" + reqXmlFAIL);
return reqXmlFAIL;
}
// return ApiResult.Failed();
//告诉微信我们处理失败,请继续调用我们的接口。好像是会重试8次。
}
}
}
\ No newline at end of file
......@@ -25,6 +25,7 @@
"DeveloperKitsPort": "63994",
"FirstPage": "pages/index/index.html",
"ByteDanceSendTemplate": "https://developer.toutiao.com/api/apps/game/template/send",
"sTenpayNotify": "http://reborn.oytour.com/api/WeChatNotify/Notify", //΢Żصַ
"RedisSetting": {
"RedisServer": "192.168.2.214",
"RedisPort": "6379",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment