C#.NET XML报文签名与验签
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Web; using System.Xml; namespace a.utils { /// <summary> /// 能处理请求报文和响应报文 /// </summary> public class RequestHandlerB { /// <summary> /// 原始内容 /// </summary> protected string content; public RequestHandlerB() { parameters = new Hashtable(); // this.httpContext = httpContext; } public RequestHandlerB(HttpContext httpContext) { parameters = new Hashtable(); this.httpContext = httpContext; } /// <summary> /// 网关url地址 /// </summary> private string gateUrl; /// <summary> /// 密钥 /// </summary> private string key; /// <summary> /// 请求的参数 /// </summary> protected Hashtable parameters; /// <summary> /// debug信息 /// </summary> private string debugInfo; protected HttpContext httpContext; /// <summary> /// 初始化函数 /// </summary> public virtual void init() { //nothing to do } /// <summary> /// 获取入口地址,不包含参数值 /// </summary> /// <returns></returns> public String getGateUrl() { return gateUrl; } /// <summary> /// 设置入口地址,不包含参数值 /// </summary> /// <param name="gateUrl">入口地址</param> public void setGateUrl(String gateUrl) { this.gateUrl = gateUrl; } /// <summary> /// 获取密钥 /// </summary> /// <returns></returns> public String getKey() { return key; } /// <summary> /// 设置密钥 /// </summary> /// <param name="key">密钥字符串</param> public void setKey(string key) { this.key = key; } /// <summary> /// 获取带参数的请求URL /// </summary> /// <returns></returns> public virtual string getRequestURL() { this.createSign(); 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 && "key".CompareTo(k) != 0) { sb.Append(k + "=" + Utils.UrlEncode(v, getCharset()) + "&"); } } //去掉最后一个& if (sb.Length > 0) { sb.Remove(sb.Length - 1, 1); } return this.getGateUrl() + "?" + sb.ToString(); } /// <summary> ///创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 /// </summary> public virtual void createSign() { 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=" + this.getKey()); string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToUpper(); this.setParameter("sign", sign); //debug信息 this.setDebugInfo(sb.ToString() + " => sign:" + sign); } /// <summary> /// 获取参数值 /// </summary> /// <param name="parameter">参数名</param> /// <returns></returns> public string getParameter(string parameter) { string s = (string)parameters[parameter]; return (null == s) ? "" : 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); } } public void doSend() { this.httpContext.Response.Redirect(this.getRequestURL()); } /// <summary> /// 获取debug信息 /// </summary> /// <returns></returns> public String getDebugInfo() { return debugInfo; } /// <summary> /// 设置debug信息 /// </summary> /// <param name="debugInfo"></param> public void setDebugInfo(String debugInfo) { this.debugInfo = debugInfo; } /// <summary> /// 获取所有参数 /// </summary> /// <returns></returns> public Hashtable getAllParameters() { return this.parameters; } /// <summary> /// 获取编码 /// </summary> /// <returns></returns> protected virtual string getCharset() { //return this.httpContext.Request.ContentEncoding.BodyName; return "utf-8"; } /// <summary> /// 设置页面提交的请求参数 /// </summary> /// <param name="paramNames">参数名</param> public void setReqParameters(string[] paramNames) { this.parameters.Clear(); foreach (string pName in paramNames) { string reqVal = this.httpContext.Request[pName]; if (String.IsNullOrEmpty(reqVal)) { continue; } this.parameters.Add(pName, reqVal); } } public virtual void createSignMCH() { /* 1.进件接口用 用的是dataSign,不是sign 2.拼接key时,不需要&key= */ 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 + "&"); } } string sighStr = sb.ToString(); sighStr = sighStr.TrimEnd('&'); sighStr += this.getKey();//和支付接口不同 string sign = MD5Util.GetMD5(sighStr, getCharset()).ToLower(); this.setParameter("dataSign", sign); //debug信息 this.setDebugInfo(sb.ToString() + " => dataSign:" + sign); } //创建md5摘要,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 //public string createSign2() //{ // 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=" + this.getKey()); // string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToUpper(); // this.setParameter("sign", sign); // return sign; //} //输出XML 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> /// 设置返回内容 /// </summary> /// <param name="content">XML内容</param> public virtual void setContent(string content) { this.content = content; XmlDocument xmlDoc = new XmlDocument(); xmlDoc.XmlResolver = null;//2018-12-3 xmlDoc.LoadXml(content); XmlNode root = xmlDoc.SelectSingleNode("xml"); XmlNodeList xnl = root.ChildNodes; foreach (XmlNode xnf in xnl) { this.setParameter(xnf.Name, xnf.InnerText); } } /// <summary> /// 是否平台签名,规则是:按参数名称a-z排序,遇到空值的参数不参加签名。 /// </summary> /// <returns></returns> public virtual Boolean isTenpaySign() { 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=" + this.getKey()); string sign = MD5Util.GetMD5(sb.ToString(), getCharset()).ToUpper(); //debug信息 this.setDebugInfo(sb.ToString() + " => sign:" + sign); return getParameter("sign").Equals(sign); } } }
--
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。
基于XML 文档根节点名称为 "xml", 签名参数名为 "sign" .
"<xml>
<a>11111</a>
<sign>11111</sign>
</xml>"
签名用
utils.RequestHandlerB rhNotify = new utils.RequestHandlerB();
//设置报文参数
rhNotify.setParameter("return_code", return_code);
rhNotify.setParameter("return_msg", return_msg);
rhNotify.setKey(agentKeyModel.agent_key);//设置代理KEY rhNotify.createSign(); //签名 string notifyToClientSign = rhNotify.getParameter("sign"); string notifyXML = rhNotify.parseXML();
验签
utils.RequestHandlerB rhValidSign = new utils.RequestHandlerB(); rhValidSign.setContent(content);//设置XML rhValidSign.setKey(wxMchModel.key);//设置代理KEY bool bValidSign = rhValidSign.isTenpaySign(); //验证签名 if (bValidSign) { scP.AppendLine("验证签名:OK"); } else { scP.AppendLine("验证签名:FAIL"); }
--

更多精彩