JsApiPay.cs 11 KB

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