实例:用C#.NET手把手教你做微信公众号开发(18)--使用微信支付给粉丝发红包

前面讲的所有都没有涉及到钱,一旦关联到钱都是非常敏感的,所以开通微信支付的过程和配置过程相对比较繁琐,本篇给出主要入口,因篇幅原因一篇文章讲不太细,但已足以帮你解决问题,希望给大家启发。

一、操作演示结果

二、微信支付配置

1、首先在微信公众号管理平台(微信公众平台)完成微信认证;然后开通微信支付;关联微信支付账号;微信认证的过程就不讲了,上两张开通微信支付的步骤,按提示一步步操作即可。

 

2、其次在微信支付管理平台(微信支付 - 中国领先的第三方支付平台 | 微信支付提供安全快捷的支付方式)完成相关配置,开通相应的功能,设置ip、域名等白名单,才可以顺利使用微信支付。

三、发红包源码

前端代码:

<%@ Page Language="C#" AutoEventWireup="true" EnableEventValidation="false" CodeFile="Test.aspx.cs" Inherits="Jjlm.Test" %>

<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">
<head id="Head1" runat="server">
    <title>发送红包测试</title>
</head>

<body style="background:#fff;">
<center>
<div style="width:95%;">
 <form id="form1" runat="server">
    </br>
	<!---->openid:<asp:TextBox runat="server" id="tbxOpenid" Width="60%" Visible="true"></asp:TextBox></br></br>
	商户名称:<asp:TextBox runat="server" id="tbxShanghu" Width="60%"></asp:TextBox></br></br>
	红包描述:<asp:TextBox runat="server" id="tbxZhufu" Width="60%"></asp:TextBox></br></br>
	红包金额:<asp:TextBox runat="server" id="tbxNum" Width="60%"></asp:TextBox></br></br>
	发送事由:<asp:TextBox runat="server" id="tbxReason" Width="60%"></asp:TextBox></br></br>
	<div style="margin-top: 10px;text-align: center;">
		<asp:Button ID="btnSendCommission" Runat="server" OnClick="Send" width="15%" Text="发送红包"></asp:Button>
	</div>	

	<asp:Label runat="server" id="lbresult" Visible="true"/>

</form>
</div>
</center>

</body>
</html>

后端代码:

using System;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Data.SqlClient;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.IO;
using System.Xml;
using System.Text;
using System.Net;
using System.Drawing;
using System.Drawing.Imaging;
using QinMing.Config;
using QinMing.WeixinPayPayment;

namespace Jjlm
{
	public partial class Test : System.Web.UI.Page
	{
		protected void Page_Load(object sender, EventArgs e)
		{
			if (!IsPostBack)
			{

			}
		}

		protected void Send(object sender, EventArgs e)
		{
			Random r = new Random();
			string ran1 = r.Next(1000, 9999).ToString();
			string out_trade_no = QinMingConfig.Weixin_MchId + DateTime.Now.ToString("yyyyMMddHHmmss") + ran1;

			QinMingWeixinPayPayment.SendRedPackOne(tbxShanghu.Text, tbxZhufu.Text, tbxOpenid.Text, tbxNum.Text, tbxReason.Text, "", out_trade_no);
			lbresult.Text = "微信红包已发出,请注意查收";
		}
	}
}

四、所用数据表

CREATE TABLE weixin_pay_payment_record
(
	open_id nvarchar(50),            --收款人openid
	payment_class nvarchar(30),      --支付类型,红包、转账到零钱等
	payment_num float,               --支付金额
	payment_time datetime,           --支付时间
	payment_reason nvarchar(200),    --支付缘由
	payment_trade_no nvarchar(50),   --支付订单号
	related_order_no nvarchar(50),   --相关订单号
	remark nvarchar(100)             --备注
)

五、类源码

下面这个类实现了两个功能,一是给指定微信用户发红包;二是给指定微信用户转账到零钱。我们上面演示的是发红包功能,下一篇文章演示转账到零钱功能。

QinMingWeixinPayPayment.cs,类源码文件放到App_Code目录中。

using System.Threading.Tasks;
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Xml.Linq;
using System.IO;
using System.Xml;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography;
using QinMing.Config;
using QinMing.WeixinContainer;
using QinMing.Tools;

namespace QinMing.WeixinPayPayment
{
    /// <summary>
    /// 企业号微信支付接口
    /// </summary>
    public static class QinMingWeixinPayPayment
    {

        /// <summary>
        /// 外部调用的向某个openid发放微信红包的方法实现
        /// </summary>
		public static bool SendRedPackOne(string shanghu, string zhufu, string openid, string RedpackNum, string RedpackReason, string RedpackRemark, string out_trade_no)
        {
            string ShName = shanghu;  //商户名称
            string ZhuFuYu = zhufu;  //红包祝福语,  "客户能看到的红包说明"
            string HuoDong = "降价联盟活动";  //活动名称,已关注公众号用户看不到,未关注公众号用户可以在微信app的服务通知中看到
            string Remark = RedpackRemark;  //备注
			string tmpBillno = "";
            string certPath = QinMingConfig.certPath;  //证书在服务器的物理位置
            int time_out = 10000;
            string data = null;  //调用现金红包接口需要的数据
            string xmlResult = null;  //现金红包接口返回的xml

            try
            {
                //创建支付应答对象
                RequestHandler packageReqHandler = new RequestHandler(null);
                //初始化
                packageReqHandler.Init();
                string nonceStr = TenPayV3Util.GetNoncestr();  //时间戳
                                                               //设置package订单参数
                packageReqHandler.SetParameter("nonce_str", nonceStr);    //随机字符串,不长于32位
                if(out_trade_no == "")
				{
					tmpBillno = QinMingConfig.Weixin_MchId + DateTime.Now.ToString("yyyyMMdd") + TenPayV3Util.BuildDailyRandomStr(10);  //商户订单号(每个订单号必须唯一)组成:mch_id+yyyymmdd+10位一天内不能重复的数字。接口根据商户订单号支持重入,如出现超时可再调用。
				}
				else
				{
					tmpBillno = out_trade_no;
				}
				
				packageReqHandler.SetParameter("mch_billno", tmpBillno);
                packageReqHandler.SetParameter("mch_id", QinMingConfig.Weixin_MchId);  //微信支付分配的商户号
                packageReqHandler.SetParameter("wxappid", QinMingConfig.Weixin_AppId);//微信分配的公众账号ID(企业号corpid即为此appId)。接口传入的所有appid应该为公众号的appid(在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)。 
                packageReqHandler.SetParameter("send_name", ShName);//商户名称  
                packageReqHandler.SetParameter("re_openid", openid);  //用户openid  接收红包的用户用户在wxappid下的openid
                                                                                    //int tmpAmount = Convert.ToInt32(dr["贡献uv"].ToString())*10;
                packageReqHandler.SetParameter("total_amount", RedpackNum);  //付款金额 单位分  tmpAmount.ToString()
                packageReqHandler.SetParameter("total_num", "1");  //红包发放总人数
                packageReqHandler.SetParameter("wishing", ZhuFuYu);  //红包祝福语
                packageReqHandler.SetParameter("client_ip", HttpContext.Current.Request.UserHostAddress);//Ip地址
                packageReqHandler.SetParameter("act_name", HuoDong);//活动名称,客户看不到
                packageReqHandler.SetParameter("remark", Remark);     //备注,客户看不到
                packageReqHandler.SetParameter("scene_id", "PRODUCT_5");  //红包发放总人数
                string sign = packageReqHandler.CreateMd5Sign("key", QinMingConfig.Weixin_MchIdKey);
                packageReqHandler.SetParameter("sign", sign);                        //签名
                data = packageReqHandler.ParseXML();
                xmlResult = QinMing.WeixinPayPayment.QinMingWeixinPayPayment.SendRedPack(data, QinMingConfig.Weixin_MchId, certPath, time_out);
                //Response.Write(xmlResult);
                var res = XDocument.Parse(xmlResult);
                string return_code = res.Element("xml").Element("return_code").Value;
                if ("SUCCESS".Equals(return_code))
                {
                    string result_code = res.Element("xml").Element("result_code").Value;
                    if ("SUCCESS".Equals(result_code))
                    {
                        //留存微信红包发送日志
						SendRedPackRecord(openid, "微信红包", RedpackNum, RedpackReason, tmpBillno, RedpackRemark);
                    }
					else
					{
						QinMingTools.WriteLog("微信支付(向指定openid发红包):", res.ToString());
					}
                }
                return true;
            }
            catch (Exception exception)
            {
                QinMingTools.WriteLog("微信支付(向指定openid发红包):", exception.ToString());
				return false;
            }
        }

        public static void SendRedPackRecord(string openid, string paymentclass, string redpack, string reason, string billno, string remark)
        {
            SqlConnection Conn = new SqlConnection(QinMingConfig.DatabaseConnStr);
            Conn.Open();
            SqlCommand Comm = new SqlCommand();
            Comm.Connection = Conn;
            Comm.CommandText = "insert into weixin_pay_payment_record (open_id, payment_class, payment_num, payment_time, payment_reason, payment_trade_no, remark) values "
                        + " ('" + openid + "','" + paymentclass + "'," + redpack + ",getdate(),'" + reason + "','" + billno + "','" + remark + "')";
            Comm.ExecuteScalar();
            if (Conn.State == ConnectionState.Open)
            {
                Conn.Close();
                Conn.Dispose();
            }
        }

        #region 内部调用企业向用户发红包
        /// <summary>
        /// 用于企业向微信用户个人发红包
        /// 目前支持向指定微信用户的openid个人发红包;不管用户是否关注公众号都能收到,未关注情况下在服务通知里收取红包
        /// </summary>
        /// <param name="certPassword">apiclient_cert.p12证书密码即商户号</param>
        /// <param name="data">微信支付需要post的xml数据</param>
        /// <param name="certPath">apiclient_cert.p12的证书物理位置(例如:E:\projects\文档\微信商户平台证书\商户平台API证书</param>
        /// <param name="timeOut"></param>
        /// <returns></returns>
        public static string SendRedPack(string data, string certPassword, string certPath, int timeOut)
        {
            var urlFormat = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
            string cert = certPath;

            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            X509Certificate2 cer = new X509Certificate2(cert, certPassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);

            var formDataBytes = data == null ? new byte[0] : Encoding.UTF8.GetBytes(data);
            MemoryStream ms = new MemoryStream();
            ms.Write(formDataBytes, 0, formDataBytes.Length);
            ms.Seek(0, SeekOrigin.Begin);//设置指针读取位置

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlFormat);
            request.ClientCertificates.Add(cer);
            request.Method = "POST";
            request.Timeout = timeOut;

            request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36";

            #region 输入二进制流
            if (ms != null)
            {
                ms.Position = 0;
                //直接写入流
                Stream requestStream = request.GetRequestStream();
                byte[] buffer = new byte[1024];
                int bytesRead = 0;
                while ((bytesRead = ms.Read(buffer, 0, buffer.Length)) != 0)
                {
                    requestStream.Write(buffer, 0, bytesRead);
                }
                ms.Close();//关闭文件访问
            }
            #endregion

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            using (Stream responseStream = response.GetResponseStream())
            {
                using (StreamReader myStreamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")))
                {
                    string retString = myStreamReader.ReadToEnd();
                    return retString;
                }
            }
        }
		
		/// <summary>
        /// 外部调用的向某个openid零钱转账的方法实现
		///TransferAccountRemark不能为空
        /// </summary>
		public static bool TransferAccountOne(string shanghu, string zhufu, string openid, string TransferAccountNum, string TransferAccountReason, string TransferAccountRemark, string out_trade_no)
        {
			string certPath = QinMingConfig.certPath;  //证书在服务器的物理位置
			//certPath = @"e:\web\weixin\apiclient_cert.p12";   //@"F:\apiclient_cert.p12";    Server.MapPath("~/") + ""
			int time_out = 10000;
			string data = null;  //调用现金红包接口需要的数据
			string xmlResult = null;  //现金红包接口返回的xml
			string tmpBillno = "";

			try
			{
				//创建支付应答对象
				RequestHandler packageReqHandler = new RequestHandler(null);
				//初始化
				packageReqHandler.Init();
				string nonceStr = TenPayV3Util.GetNoncestr();  //时间戳
				//设置package订单参数
				packageReqHandler.SetParameter("nonce_str", nonceStr);    //随机字符串,不长于32位
				if(out_trade_no == "")
				{
					tmpBillno = QinMingConfig.Weixin_MchId + DateTime.Now.ToString("yyyyMMdd") + TenPayV3Util.BuildDailyRandomStr(10);  //商户订单号(每个订单号必须唯一)组成:mch_id+yyyymmdd+10位一天内不能重复的数字。接口根据商户订单号支持重入,如出现超时可再调用。
				}
				else
				{
					tmpBillno = out_trade_no;
				}
				
				packageReqHandler.SetParameter("partner_trade_no", tmpBillno);
				packageReqHandler.SetParameter("mchid", QinMingConfig.Weixin_MchId);  //微信支付分配的商户号
				packageReqHandler.SetParameter("mch_appid", QinMingConfig.Weixin_AppId);//微信分配的公众账号ID(企业号corpid即为此appId)。接口传入的所有appid应该为公众号的appid(在mp.weixin.qq.com申请的),不能为APP的appid(在open.weixin.qq.com申请的)。 
				packageReqHandler.SetParameter("check_name", "NO_CHECK");//商户名称  
				packageReqHandler.SetParameter("openid", openid);  //用户openid  
				packageReqHandler.SetParameter("amount", TransferAccountNum);  //付款金额 单位分  
				packageReqHandler.SetParameter("desc", TransferAccountRemark);  //红包发放总人数
				packageReqHandler.SetParameter("spbill_create_ip", "192.168.0.1");  //红包祝福语
				string sign = packageReqHandler.CreateMd5Sign("key", QinMingConfig.Weixin_MchIdKey);
				packageReqHandler.SetParameter("sign", sign);                        //签名
				data = packageReqHandler.ParseXML();
				xmlResult = QinMing.WeixinPayPayment.QinMingWeixinPayPayment.TransferAccount(data, QinMingConfig.Weixin_MchId, certPath, time_out);
				//Response.Write(xmlResult);
				var res = XDocument.Parse(xmlResult);
				string return_code = res.Element("xml").Element("return_code").Value;
				if ("SUCCESS".Equals(return_code))
				{
					string result_code = res.Element("xml").Element("result_code").Value;
					if ("SUCCESS".Equals(result_code))
					{
						TransferAccountRecord(openid, "微信转账到零钱", TransferAccountNum, TransferAccountReason, tmpBillno, TransferAccountRemark);
					}
					else
					{
						QinMingTools.WriteLog("微信支付(向指定openid零钱转账):", res.ToString());
					}
				}
				return true;
			}
			catch (Exception exception)
			{
				QinMingTools.WriteLog("微信支付(向指定openid零钱转账):", exception.ToString());
				return false;
			}
		}
		
		public static void TransferAccountRecord(string openid, string paymentclass, string transferaccount, string reason, string billno, string remark)
        {
            SqlConnection Conn = new SqlConnection(QinMingConfig.DatabaseConnStr);
            Conn.Open();
            SqlCommand Comm = new SqlCommand();
            Comm.Connection = Conn;
            Comm.CommandText = "insert into weixin_pay_payment_record (open_id, payment_class, payment_num, payment_time, payment_reason, payment_trade_no, remark) values "
                        + " ('" + openid + "','" + paymentclass + "'," + transferaccount + ",getdate(),'" + reason + "','" + billno + "','" + remark + "')";
            Comm.ExecuteScalar();
            if (Conn.State == ConnectionState.Open)
            {
                Conn.Close();
                Conn.Dispose();
            }
        }

        /// <summary>
        /// 内部调用企业向微信用户个人转帐,直接到零钱
        /// 目前支持向指定微信用户的openid个人转帐
        /// </summary>
        public static string TransferAccount(string data, string certPassword, string certPath, int timeOut)
        {
            var urlFormat = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
            string cert = certPath;

            ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
            X509Certificate2 cer = new X509Certificate2(cert, certPassword, X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet);

            var formDataBytes = data == null ? new byte[0] : Encoding.UTF8.GetBytes(data);
            MemoryStream ms = new MemoryStream();
            ms.Write(formDataBytes, 0, formDataBytes.Length);
            ms.Seek(0, SeekOrigin.Begin);//设置指针读取位置

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlFormat);
            request.ClientCertificates.Add(cer);
            request.Method = "POST";
            request.Timeout = timeOut;

            request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36";

            #region 输入二进制流
            if (ms != null)
            {
                ms.Position = 0;
                //直接写入流
                Stream requestStream = request.GetRequestStream();
                byte[] buffer = new byte[1024];
                int bytesRead = 0;
                while ((bytesRead = ms.Read(buffer, 0, buffer.Length)) != 0)
                {
                    requestStream.Write(buffer, 0, bytesRead);
                }
                ms.Close();//关闭文件访问
            }
            #endregion

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();

            using (Stream responseStream = response.GetResponseStream())
            {
                using (StreamReader myStreamReader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8")))
                {
                    string retString = myStreamReader.ReadToEnd();
                    return retString;
                }
            }
        }
		
        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            if (errors == SslPolicyErrors.None)
                return true;
            return false;
        }
        #endregion

    }

    /// <summary>
    /// MD5UtilHelper 的摘要说明。
    /// </summary>
    public class MD5UtilHelper
    {
        public MD5UtilHelper()
        {
            //
            // TODO: 在此处添加构造函数逻辑
            //
        }

        /// <summary>
        /// 获取大写的MD5签名结果
        /// </summary>
        /// <param name="encypStr"></param>
        /// <param name="charset"></param>
        /// <returns></returns>
        public static string GetMD5(string encypStr, string charset)
        {
            string retStr;
            MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider();

            //创建md5对象
            byte[] inputBye;
            byte[] outputBye;

            //使用GB2312编码方式把字符串转化为字节数组.
            try
            {
                inputBye = Encoding.GetEncoding(charset).GetBytes(encypStr);
            }
            catch (Exception ex)
            {
                inputBye = Encoding.GetEncoding("GB2312").GetBytes(encypStr);
            }
            outputBye = m5.ComputeHash(inputBye);

            retStr = System.BitConverter.ToString(outputBye);
            retStr = retStr.Replace("-", "").ToUpper();
            return retStr;
        }
    }

    public class RequestHandler
    {

        public RequestHandler(HttpContext httpContext)
        {
            Parameters = new Hashtable();

            this.HttpContext = httpContext ?? HttpContext.Current;

        }
        /// <summary>
        /// 密钥
        /// </summary>
        private string Key;

        protected HttpContext HttpContext;

        /// <summary>
        /// 请求的参数
        /// </summary>
        protected Hashtable Parameters;

        /// <summary>
        /// debug信息
        /// </summary>
        private string DebugInfo;

        /// <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 (parameter != null && parameter != "")
            {
                if (Parameters.Contains(parameter))
                {
                    Parameters.Remove(parameter);
                }

                Parameters.Add(parameter, parameterValue);
            }
        }


        /// <summary>
        /// 创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名
        /// </summary>
        /// <param name="key">参数名</param>
        /// <param name="value">参数值</param>
        /// key和value通常用于填充最后一组参数
        /// <returns></returns>
        public virtual string CreateMd5Sign(string key, string value)
        {
            StringBuilder sb = new StringBuilder();

            ArrayList akeys = new ArrayList(Parameters.Keys);
            akeys.Sort();

            foreach (string k in akeys)
            {
                string v = (string)Parameters[k];
                if (null != v && "".CompareTo(v) != 0
                    && "sign".CompareTo(k) != 0 && "key".CompareTo(k) != 0)
                {
                    sb.Append(k + "=" + v + "&");
                }
            }

            sb.Append(key + "=" + value);
            string sign = MD5UtilHelper.GetMD5(sb.ToString(), GetCharset()).ToUpper();

            return sign;
        }

        /// <summary>
        /// 输出XML
        /// </summary>
        /// <returns></returns>
        public string ParseXML()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("<xml>");
            foreach (string k in Parameters.Keys)
            {
                string 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>
        /// 设置debug信息
        /// </summary>
        /// <param name="debugInfo"></param>
        public void SetDebugInfo(String debugInfo)
        {
            this.DebugInfo = debugInfo;
        }

        public Hashtable GetAllParameters()
        {
            return this.Parameters;
        }

        protected virtual string GetCharset()
        {
            return this.HttpContext.Request.ContentEncoding.BodyName;
        }
    }


    public class TenPayV3Util
    {
        public static Random random = new Random();

        /// <summary>
        /// 随机生成Noncestr
        /// </summary>
        /// <returns></returns>
        public static string GetNoncestr()
        {
            return EncryptHelper.GetMD5(Guid.NewGuid().ToString(), "UTF-8");
        }

        /// <summary>
        /// 获取微信时间格式
        /// </summary>
        /// <returns></returns>
        public static string GetTimestamp()
        {
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            return Convert.ToInt64(ts.TotalSeconds).ToString();
        }

        /// <summary>
        /// 对字符串进行URL编码
        /// </summary>
        /// <param name="instr"></param>
        /// <param name="charset"></param>
        /// <returns></returns>
        public static string UrlEncode(string instr, string charset)
        {
            //return instr;
            if (instr == null || instr.Trim() == "")
                return "";
            else
            {
                //string res;

                try
                {
                    return System.Web.HttpUtility.UrlEncode(instr, Encoding.GetEncoding(charset));
                }
                catch (Exception ex)
                {
                    return System.Web.HttpUtility.UrlEncode(instr, Encoding.GetEncoding("GB2312"));
                }

                //return res;
            }
        }

        /// <summary>
        /// 对字符串进行URL解码
        /// </summary>
        /// <param name="instr"></param>
        /// <param name="charset"></param>
        /// <returns></returns>
        public static string UrlDecode(string instr, string charset)
        {
            if (instr == null || instr.Trim() == "")
                return "";
            else
            {
                //string res;

                try
                {
                    return System.Web.HttpUtility.UrlDecode(instr, Encoding.GetEncoding(charset));
                }
                catch (Exception ex)
                {
                    return System.Web.HttpUtility.UrlDecode(instr, Encoding.GetEncoding("GB2312"));
                }
                //return res;

            }
        }


        /// <summary>
        /// 取时间戳生成随即数,替换交易单号中的后10位流水号
        /// </summary>
        /// <returns></returns>
        public static UInt32 UnixStamp()
        {
            TimeSpan ts = DateTime.Now - TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
            return Convert.ToUInt32(ts.TotalSeconds);
        }

        /// <summary>
        /// 取随机数
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string BuildRandomStr(int length)
        {
            int num;

            lock (random)
            {
                num = random.Next();
            }

            string str = num.ToString();

            if (str.Length > length)
            {
                str = str.Substring(0, length);
            }
            else if (str.Length < length)
            {
                int n = length - str.Length;
                while (n > 0)
                {
                    str = str.Insert(0, "0");
                    n--;
                }
            }

            return str;
        }

        /// <summary>
        /// 创建当天内不会重复的数字
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string BuildDailyRandomStr(int length)
        {
            Random r = new Random();
            int i = r.Next(1000, 9999);
            var stringFormat = DateTime.Now.ToString("HHmmss" + i.ToString());//共10位

            return stringFormat;
        }


        /// <summary>
        /// 对退款通知消息进行解密
        /// </summary>
        /// <param name="reqInfo"></param>
        /// <param name="mchKey"></param>
        /// <returns></returns>
        public static string DecodeRefundReqInfo(string reqInfo, string mchKey)
        {
            //参考文档:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=9_16&index=11
            /*
               解密步骤如下: 
                (1)对加密串A做base64解码,得到加密串B
                (2)对商户key做md5,得到32位小写key* ( key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 )

                (3)用key*对加密串B做AES-256-ECB解密(PKCS7Padding)
             */
            //var base64Encode = Encoding.UTF8.GetString(Convert.FromBase64String(reqInfo));//(1)
            var base64Encode = reqInfo;//(1) EncryptHelper.AESDecrypt 方法内部会进行一次base64解码,因此这里不再需要解码
            var md5Str = EncryptHelper.GetLowerMD5(mchKey, Encoding.UTF8);//(2)
            var result = EncryptHelper.AESDecrypt(base64Encode, md5Str);//(3)
            return result;
        }
    }


    /// <summary>
    /// 安全帮助类,提供SHA-1算法等
    /// </summary>
    public class EncryptHelper
    {
        #region SHA相关

        /// <summary>
        /// 采用SHA-1算法加密字符串(小写)
        /// </summary>
        /// <param name="encypStr">需要加密的字符串</param>
        /// <returns></returns>
        public static string GetSha1(string encypStr)
        {
            var sha1 = SHA1.Create();
            var sha1Arr = sha1.ComputeHash(Encoding.UTF8.GetBytes(encypStr));
            StringBuilder enText = new StringBuilder();
            foreach (var b in sha1Arr)
            {
                enText.AppendFormat("{0:x2}", b);
            }

            return enText.ToString();

            //byte[] strRes = Encoding.Default.GetBytes(encypStr);
            //HashAlgorithm iSHA = new SHA1CryptoServiceProvider();
            //strRes = iSHA.ComputeHash(strRes);
            //StringBuilder enText = new StringBuilder();
            //foreach (byte iByte in strRes)
            //{
            //    enText.AppendFormat("{0:x2}", iByte);
            //}
        }

        /// <summary>
        /// HMAC SHA256 加密
        /// </summary>
        /// <param name="message">加密消息原文。当为小程序SessionKey签名提供服务时,其中message为本次POST请求的数据包(通常为JSON)。特别地,对于GET请求,message等于长度为0的字符串。</param>
        /// <param name="secret">秘钥(如小程序的SessionKey)</param>
        /// <returns></returns>
        public static string GetHmacSha256(string message, string secret)
        {
            message = message ?? "";
            secret = secret ?? "";
            byte[] keyByte = Encoding.UTF8.GetBytes(secret);
            byte[] messageBytes = Encoding.UTF8.GetBytes(message);
            using (var hmacsha256 = new HMACSHA256(keyByte))
            {
                byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                StringBuilder enText = new StringBuilder();
                foreach (var b in hashmessage)
                {
                    enText.AppendFormat("{0:x2}", b);
                }
                return enText.ToString();
            }
        }


        #endregion

        #region MD5

        /// <summary>
        /// 获取大写的MD5签名结果
        /// </summary>
        /// <param name="encypStr">需要加密的字符串</param>
        /// <param name="encoding">编码</param>
        /// <returns></returns>
        public static string GetMD5(string encypStr, Encoding encoding)
        {
            string retStr;

            MD5CryptoServiceProvider m5 = new MD5CryptoServiceProvider();

            //创建md5对象
            byte[] inputBye;
            byte[] outputBye;

            //使用指定编码方式把字符串转化为字节数组.
            try
            {
                inputBye = encoding.GetBytes(encypStr);
            }
            catch
            {
                inputBye = Encoding.GetEncoding("utf-8").GetBytes(encypStr);

            }
            outputBye = m5.ComputeHash(inputBye);

            retStr = BitConverter.ToString(outputBye);
            retStr = retStr.Replace("-", "").ToUpper();
            return retStr;
        }

        /// <summary>
        /// 获取大写的MD5签名结果
        /// </summary>
        /// <param name="encypStr">需要加密的字符串</param>
        /// <param name="charset">编码</param>
        /// <returns></returns>
        public static string GetMD5(string encypStr, string charset = "utf-8")
        {
            charset = charset ?? "utf-8";
            try
            {
                //使用指定编码
                return GetMD5(encypStr, Encoding.GetEncoding(charset));
            }
            catch (Exception ex)
            {
                //使用UTF-8编码
                return GetMD5("utf-8", Encoding.GetEncoding(charset));

                //#if NET35 || NET40 || NET45
                //                inputBye = Encoding.GetEncoding("GB2312").GetBytes(encypStr);
                //#else
                //                inputBye = Encoding.GetEncoding(936).GetBytes(encypStr);
                //#endif
            }
        }

        /// <summary>
        /// 获取小写的MD5签名结果
        /// </summary>
        /// <param name="encypStr">需要加密的字符串</param>
        /// <param name="encoding">编码</param>
        /// <returns></returns>
        public static string GetLowerMD5(string encypStr, Encoding encoding)
        {
            return GetMD5(encypStr, encoding).ToLower();
        }

        #endregion

        #region AES

        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="inputdata">输入的数据</param>
        /// <param name="iv">向量</param>
        /// <param name="strKey">加密密钥</param>
        /// <returns></returns>
        public static byte[] AESEncrypt(byte[] inputdata, byte[] iv, string strKey)
        {
            //分组加密算法   
            SymmetricAlgorithm des = Rijndael.Create();

            byte[] inputByteArray = inputdata;//得到需要加密的字节数组       
                                              //设置密钥及密钥向量
            des.Key = Encoding.UTF8.GetBytes(strKey.Substring(0, 32));
            des.IV = iv;
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(inputByteArray, 0, inputByteArray.Length);
                    cs.FlushFinalBlock();
                    byte[] cipherBytes = ms.ToArray();//得到加密后的字节数组   
                    //cs.Close();
                    //ms.Close();
                    return cipherBytes;
                }
            }
        }


        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="inputdata">输入的数据</param>
        /// <param name="iv">向量</param>
        /// <param name="strKey">key</param>
        /// <returns></returns>
        public static byte[] AESDecrypt(byte[] inputdata, byte[] iv, byte[] strKey)
        {
            SymmetricAlgorithm des = Rijndael.Create();

            des.Key = strKey;//Encoding.UTF8.GetBytes(strKey);//.Substring(0, 7)
            des.IV = iv;
            byte[] decryptBytes = new byte[inputdata.Length];
            using (MemoryStream ms = new MemoryStream(inputdata))
            {
                using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Read))
                {
                    cs.Read(decryptBytes, 0, decryptBytes.Length);
                    //cs.Close();
                    //ms.Close();
                }
            }
            return decryptBytes;
        }

        /// <summary>  
        /// AES解密(无向量)  
        /// </summary>  
        /// <param name="data">被加密的明文</param>  
        /// <param name="key">密钥</param>  
        /// <returns>明文</returns>  
        public static string AESDecrypt(String data, String key)
        {
            Byte[] encryptedBytes = Convert.FromBase64String(data);
            Byte[] bKey = new Byte[32];
            Array.Copy(Encoding.UTF8.GetBytes(key.PadRight(bKey.Length)), bKey, bKey.Length);

            MemoryStream mStream = new MemoryStream(encryptedBytes);
            //mStream.Write( encryptedBytes, 0, encryptedBytes.Length );  
            //mStream.Seek( 0, SeekOrigin.Begin );  


            //RijndaelManaged aes = new RijndaelManaged();
            SymmetricAlgorithm aes = Rijndael.Create();

            aes.Mode = CipherMode.ECB;
            aes.Padding = PaddingMode.PKCS7;
            aes.KeySize = 128;
            aes.Key = bKey;
            //aes.IV = _iV;  
            CryptoStream cryptoStream = new CryptoStream(mStream, aes.CreateDecryptor(), CryptoStreamMode.Read);
            try
            {
                byte[] tmp = new byte[encryptedBytes.Length + 32];
                int len = cryptoStream.Read(tmp, 0, encryptedBytes.Length + 32);
                byte[] ret = new byte[len];
                Array.Copy(tmp, 0, ret, 0, len);
                return Encoding.UTF8.GetString(ret);
            }
            finally
            {
                cryptoStream.Close();
                mStream.Close();
                aes.Clear();
            }
        }

        #endregion
    }

}

猜你喜欢

转载自blog.csdn.net/daobaqin/article/details/125073605