JsApiPay.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Web;
  4. using System.Web.UI;
  5. using System.Web.UI.WebControls;
  6. using System.Runtime.Serialization;
  7. using System.IO;
  8. using System.Text;
  9. using System.Net;
  10. using System.Web.Security;
  11. using LitJson;
  12. namespace LYFZ.WxPayAPI
  13. {
  14. public class JsApiPay
  15. {
  16. /// <summary>
  17. /// 保存页面对象,因为要在类的方法中使用Page的Request对象
  18. /// </summary>
  19. private Page page {get;set;}
  20. /// <summary>
  21. /// openid用于调用统一下单接口
  22. /// </summary>
  23. public string openid { get; set; }
  24. /// <summary>
  25. /// access_token用于获取收货地址js函数入口参数
  26. /// </summary>
  27. public string access_token { get; set; }
  28. /// <summary>
  29. /// 商品金额,用于统一下单
  30. /// </summary>
  31. public int total_fee { get; set; }
  32. /// <summary>
  33. /// 统一下单接口返回结果
  34. /// </summary>
  35. public WxPayData unifiedOrderResult { get; set; }
  36. public JsApiPay(Page page)
  37. {
  38. this.page = page;
  39. }
  40. /**
  41. *
  42. * 网页授权获取用户基本信息的全部过程
  43. * 详情请参看网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
  44. * 第一步:利用url跳转获取code
  45. * 第二步:利用code去获取openid和access_token
  46. *
  47. */
  48. public void GetOpenidAndAccessToken()
  49. {
  50. if (!string.IsNullOrEmpty(page.Request.QueryString["code"]))
  51. {
  52. //获取code码,以获取openid和access_token
  53. string code = page.Request.QueryString["code"];
  54. Log.Debug(this.GetType().ToString(), "Get code : " + code);
  55. GetOpenidAndAccessTokenFromCode(code);
  56. }
  57. else
  58. {
  59. //构造网页授权获取code的URL
  60. string host = page.Request.Url.Host;
  61. string path = page.Request.Path;
  62. string redirect_uri = HttpUtility.UrlEncode("http://" + host + path);
  63. WxPayData data = new WxPayData();
  64. data.SetValue("appid", WxPayConfig.APPID);
  65. data.SetValue("redirect_uri", redirect_uri);
  66. data.SetValue("response_type", "code");
  67. data.SetValue("scope", "snsapi_base");
  68. data.SetValue("state", "STATE" + "#wechat_redirect");
  69. string url = "https://open.weixin.qq.com/connect/oauth2/authorize?" + data.ToUrl();
  70. Log.Debug(this.GetType().ToString(), "Will Redirect to URL : " + url);
  71. try
  72. {
  73. //触发微信返回code码
  74. page.Response.Redirect(url);//Redirect函数会抛出ThreadAbortException异常,不用处理这个异常
  75. }
  76. catch
  77. {
  78. }
  79. }
  80. }
  81. /**
  82. *
  83. * 通过code换取网页授权access_token和openid的返回数据,正确时返回的JSON数据包如下:
  84. * {
  85. * "access_token":"ACCESS_TOKEN",
  86. * "expires_in":7200,
  87. * "refresh_token":"REFRESH_TOKEN",
  88. * "openid":"OPENID",
  89. * "scope":"SCOPE",
  90. * "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
  91. * }
  92. * 其中access_token可用于获取共享收货地址
  93. * openid是微信支付jsapi支付接口统一下单时必须的参数
  94. * 更详细的说明请参考网页授权获取用户基本信息:http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html
  95. * @失败时抛异常WxPayException
  96. */
  97. public void GetOpenidAndAccessTokenFromCode(string code)
  98. {
  99. try
  100. {
  101. //构造获取openid及access_token的url
  102. WxPayData data = new WxPayData();
  103. data.SetValue("appid", WxPayConfig.APPID);
  104. data.SetValue("secret", WxPayConfig.APPSECRET);
  105. data.SetValue("code", code);
  106. data.SetValue("grant_type", "authorization_code");
  107. string url = "https://api.weixin.qq.com/sns/oauth2/access_token?" + data.ToUrl();
  108. //请求url以获取数据
  109. string result = HttpService.Get(url);
  110. Log.Debug(this.GetType().ToString(), "GetOpenidAndAccessTokenFromCode response : " + result);
  111. //保存access_token,用于收货地址获取
  112. JsonData jd = JsonMapper.ToObject(result);
  113. access_token = (string)jd["access_token"];
  114. //获取用户openid
  115. openid = (string)jd["openid"];
  116. Log.Debug(this.GetType().ToString(), "Get openid : " + openid);
  117. Log.Debug(this.GetType().ToString(), "Get access_token : " + access_token);
  118. }
  119. catch (Exception ex)
  120. {
  121. Log.Error(this.GetType().ToString(), ex.ToString());
  122. throw new WxPayException(ex.ToString());
  123. }
  124. }
  125. /**
  126. * 调用统一下单,获得下单结果
  127. * @return 统一下单结果
  128. * @失败时抛异常WxPayException
  129. */
  130. public WxPayData GetUnifiedOrderResult()
  131. {
  132. //统一下单
  133. WxPayData data = new WxPayData();
  134. data.SetValue("body", "test");
  135. data.SetValue("attach", "test");
  136. data.SetValue("out_trade_no", WxPayApi.GenerateOutTradeNo());
  137. data.SetValue("total_fee", total_fee);
  138. data.SetValue("time_start", DateTime.Now.ToString("yyyyMMddHHmmss"));
  139. data.SetValue("time_expire", DateTime.Now.AddMinutes(10).ToString("yyyyMMddHHmmss"));
  140. data.SetValue("goods_tag", "test");
  141. data.SetValue("trade_type", "JSAPI");
  142. data.SetValue("openid", openid);
  143. WxPayData result = WxPayApi.UnifiedOrder(data);
  144. if (!result.IsSet("appid") || !result.IsSet("prepay_id") || result.GetValue("prepay_id").ToString() == "")
  145. {
  146. Log.Error(this.GetType().ToString(), "UnifiedOrder response error!");
  147. throw new WxPayException("UnifiedOrder response error!");
  148. }
  149. unifiedOrderResult = result;
  150. return result;
  151. }
  152. /**
  153. *
  154. * 从统一下单成功返回的数据中获取微信浏览器调起jsapi支付所需的参数,
  155. * 微信浏览器调起JSAPI时的输入参数格式如下:
  156. * {
  157. * "appId" : "wx2421b1c4370ec43b", //公众号名称,由商户传入
  158. * "timeStamp":" 1395712654", //时间戳,自1970年以来的秒数
  159. * "nonceStr" : "e61463f8efa94090b1f366cccfbbb444", //随机串
  160. * "package" : "prepay_id=u802345jgfjsdfgsdg888",
  161. * "signType" : "MD5", //微信签名方式:
  162. * "paySign" : "70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名
  163. * }
  164. * @return string 微信浏览器调起JSAPI时的输入参数,json格式可以直接做参数用
  165. * 更详细的说明请参考网页端调起支付API:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7
  166. *
  167. */
  168. public string GetJsApiParameters()
  169. {
  170. Log.Debug(this.GetType().ToString(), "JsApiPay::GetJsApiParam is processing...");
  171. WxPayData jsApiParam = new WxPayData();
  172. jsApiParam.SetValue("appId", unifiedOrderResult.GetValue("appid"));
  173. jsApiParam.SetValue("timeStamp", WxPayApi.GenerateTimeStamp());
  174. jsApiParam.SetValue("nonceStr", WxPayApi.GenerateNonceStr());
  175. jsApiParam.SetValue("package", "prepay_id=" + unifiedOrderResult.GetValue("prepay_id"));
  176. jsApiParam.SetValue("signType", "MD5");
  177. jsApiParam.SetValue("paySign", jsApiParam.MakeSign());
  178. string parameters = jsApiParam.ToJson();
  179. Log.Debug(this.GetType().ToString(), "Get jsApiParam : " + parameters);
  180. return parameters;
  181. }
  182. /**
  183. *
  184. * 获取收货地址js函数入口参数,详情请参考收货地址共享接口:http://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_9
  185. * @return string 共享收货地址js函数需要的参数,json格式可以直接做参数使用
  186. */
  187. public string GetEditAddressParameters()
  188. {
  189. string parameter = "";
  190. try
  191. {
  192. string host = page.Request.Url.Host;
  193. string path = page.Request.Path;
  194. string queryString = page.Request.Url.Query;
  195. //这个地方要注意,参与签名的是网页授权获取用户信息时微信后台回传的完整url
  196. string url = "http://" + host + path + queryString;
  197. //构造需要用SHA1算法加密的数据
  198. WxPayData signData = new WxPayData();
  199. signData.SetValue("appid",WxPayConfig.APPID);
  200. signData.SetValue("url", url);
  201. signData.SetValue("timestamp",WxPayApi.GenerateTimeStamp());
  202. signData.SetValue("noncestr",WxPayApi.GenerateNonceStr());
  203. signData.SetValue("accesstoken",access_token);
  204. string param = signData.ToUrl();
  205. Log.Debug(this.GetType().ToString(), "SHA1 encrypt param : " + param);
  206. //SHA1加密
  207. string addrSign = FormsAuthentication.HashPasswordForStoringInConfigFile(param, "SHA1");
  208. Log.Debug(this.GetType().ToString(), "SHA1 encrypt result : " + addrSign);
  209. //获取收货地址js函数入口参数
  210. WxPayData afterData = new WxPayData();
  211. afterData.SetValue("appId",WxPayConfig.APPID);
  212. afterData.SetValue("scope","jsapi_address");
  213. afterData.SetValue("signType","sha1");
  214. afterData.SetValue("addrSign",addrSign);
  215. afterData.SetValue("timeStamp",signData.GetValue("timestamp"));
  216. afterData.SetValue("nonceStr",signData.GetValue("noncestr"));
  217. //转为json格式
  218. parameter = afterData.ToJson();
  219. Log.Debug(this.GetType().ToString(), "Get EditAddressParam : " + parameter);
  220. }
  221. catch (Exception ex)
  222. {
  223. Log.Error(this.GetType().ToString(), ex.ToString());
  224. throw new WxPayException(ex.ToString());
  225. }
  226. return parameter;
  227. }
  228. }
  229. }