WechatApiHttpClient.cs 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
  2. //
  3. // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
  4. //
  5. // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
  6. using Newtonsoft.Json;
  7. namespace Admin.NET.Core.Service;
  8. /// <summary>
  9. /// 微信API客户端
  10. /// </summary>
  11. public partial class WechatApiClientFactory : ISingleton
  12. {
  13. private readonly IHttpClientFactory _httpClientFactory;
  14. public readonly WechatOptions _wechatOptions;
  15. private readonly SysCacheService _sysCacheService;
  16. public WechatApiClientFactory(IHttpClientFactory httpClientFactory, IOptions<WechatOptions> wechatOptions, SysCacheService sysCacheService)
  17. {
  18. _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
  19. _wechatOptions = wechatOptions.Value ?? throw new ArgumentNullException(nameof(wechatOptions));
  20. _sysCacheService = sysCacheService;
  21. }
  22. /// <summary>
  23. /// 微信公众号
  24. /// </summary>
  25. /// <returns></returns>
  26. public WechatApiClient CreateWechatClient()
  27. {
  28. if (string.IsNullOrEmpty(_wechatOptions.WechatAppId) || string.IsNullOrEmpty(_wechatOptions.WechatAppSecret))
  29. throw Oops.Oh("微信公众号配置错误");
  30. var client = WechatApiClientBuilder.Create(new WechatApiClientOptions()
  31. {
  32. AppId = _wechatOptions.WechatAppId,
  33. AppSecret = _wechatOptions.WechatAppSecret,
  34. PushToken = _wechatOptions.WechatToken,
  35. PushEncodingAESKey = _wechatOptions.WechatEncodingAESKey,
  36. })
  37. .UseHttpClient(_httpClientFactory.CreateClient(), disposeClient: false) // 设置 HttpClient 不随客户端一同销毁
  38. .Build();
  39. client.Configure(config =>
  40. {
  41. JsonSerializerSettings jsonSerializerSettings = NewtonsoftJsonSerializer.GetDefaultSerializerSettings();
  42. jsonSerializerSettings.Formatting = Formatting.Indented;
  43. config.JsonSerializer = new NewtonsoftJsonSerializer(jsonSerializerSettings); // 指定 System.Text.Json JSON序列化
  44. // config.JsonSerializer = new SystemTextJsonSerializer(jsonSerializerOptions); // 指定 Newtonsoft.Json JSON序列化
  45. });
  46. return client;
  47. }
  48. /// <summary>
  49. /// 微信小程序
  50. /// </summary>
  51. /// <returns></returns>
  52. public WechatApiClient CreateWxOpenClient()
  53. {
  54. if (string.IsNullOrEmpty(_wechatOptions.WxOpenAppId) || string.IsNullOrEmpty(_wechatOptions.WxOpenAppSecret))
  55. throw Oops.Oh("微信小程序配置错误");
  56. var client = WechatApiClientBuilder.Create(new WechatApiClientOptions()
  57. {
  58. AppId = _wechatOptions.WxOpenAppId,
  59. AppSecret = _wechatOptions.WxOpenAppSecret,
  60. PushToken = _wechatOptions.WxToken,
  61. PushEncodingAESKey = _wechatOptions.WxEncodingAESKey,
  62. })
  63. .UseHttpClient(_httpClientFactory.CreateClient(), disposeClient: false) // 设置 HttpClient 不随客户端一同销毁
  64. .Build();
  65. client.Configure(config =>
  66. {
  67. JsonSerializerSettings jsonSerializerSettings = NewtonsoftJsonSerializer.GetDefaultSerializerSettings();
  68. jsonSerializerSettings.Formatting = Formatting.Indented;
  69. config.JsonSerializer = new NewtonsoftJsonSerializer(jsonSerializerSettings); // 指定 System.Text.Json JSON序列化
  70. // config.JsonSerializer = new SystemTextJsonSerializer(jsonSerializerOptions); // 指定 Newtonsoft.Json JSON序列化
  71. });
  72. return client;
  73. }
  74. /// <summary>
  75. /// 获取微信公众号AccessToken
  76. /// </summary>
  77. /// <returns></returns>
  78. public async Task<string> TryGetWechatAccessTokenAsync()
  79. {
  80. if (!_sysCacheService.ExistKey($"WxAccessToken_{_wechatOptions.WechatAppId}") || string.IsNullOrEmpty(_sysCacheService.Get<string>($"WxAccessToken_{_wechatOptions.WechatAppId}")))
  81. {
  82. var client = CreateWechatClient();
  83. var reqCgibinToken = new CgibinTokenRequest();
  84. var resCgibinToken = await client.ExecuteCgibinTokenAsync(reqCgibinToken);
  85. if (resCgibinToken.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
  86. throw Oops.Oh(resCgibinToken.ErrorMessage + " " + resCgibinToken.ErrorCode);
  87. _sysCacheService.Set($"WxAccessToken_{_wechatOptions.WechatAppId}", resCgibinToken.AccessToken, TimeSpan.FromSeconds(resCgibinToken.ExpiresIn - 60));
  88. }
  89. return _sysCacheService.Get<string>($"WxAccessToken_{_wechatOptions.WechatAppId}");
  90. }
  91. /// <summary>
  92. /// 获取微信小程序AccessToken
  93. /// </summary>
  94. /// <returns></returns>
  95. public async Task<string> TryGetWxOpenAccessTokenAsync()
  96. {
  97. if (!_sysCacheService.ExistKey($"WxAccessToken_{_wechatOptions.WxOpenAppId}") || string.IsNullOrEmpty(_sysCacheService.Get<string>($"WxAccessToken_{_wechatOptions.WxOpenAppId}")))
  98. {
  99. var client = CreateWxOpenClient();
  100. var reqCgibinToken = new CgibinTokenRequest();
  101. var resCgibinToken = await client.ExecuteCgibinTokenAsync(reqCgibinToken);
  102. if (resCgibinToken.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
  103. throw Oops.Oh(resCgibinToken.ErrorMessage + " " + resCgibinToken.ErrorCode);
  104. _sysCacheService.Set($"WxAccessToken_{_wechatOptions.WxOpenAppId}", resCgibinToken.AccessToken, TimeSpan.FromSeconds(resCgibinToken.ExpiresIn - 60));
  105. }
  106. return _sysCacheService.Get<string>($"WxAccessToken_{_wechatOptions.WxOpenAppId}");
  107. }
  108. /// <summary>
  109. /// 检查微信公众号AccessToken
  110. /// </summary>
  111. /// <returns></returns>
  112. public async Task CheckWechatAccessTokenAsync()
  113. {
  114. if (string.IsNullOrEmpty(_wechatOptions.WechatAppId) || string.IsNullOrEmpty(_wechatOptions.WechatAppSecret)) return;
  115. var req = new CgibinOpenApiQuotaGetRequest
  116. {
  117. AccessToken = await TryGetWxOpenAccessTokenAsync(),
  118. CgiPath = "/cgi-bin/token"
  119. };
  120. var client = CreateWechatClient();
  121. var res = await client.ExecuteCgibinOpenApiQuotaGetAsync(req);
  122. var originColor = Console.ForegroundColor;
  123. if (res.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
  124. {
  125. _sysCacheService.Remove($"WxAccessToken_{_wechatOptions.WechatAppId}");
  126. Console.ForegroundColor = ConsoleColor.Red;
  127. Console.WriteLine("【" + DateTime.Now + "】" + _wechatOptions.WxOpenAppId + " 微信公众号令牌 无效");
  128. }
  129. else
  130. {
  131. Console.ForegroundColor = ConsoleColor.Magenta;
  132. Console.WriteLine("【" + DateTime.Now + "】" + _wechatOptions.WxOpenAppId + " 微信公众号令牌 有效");
  133. }
  134. Console.ForegroundColor = originColor;
  135. }
  136. /// <summary>
  137. /// 检查微信小程序AccessToken
  138. /// </summary>
  139. /// <returns></returns>
  140. public async Task CheckWxOpenAccessTokenAsync()
  141. {
  142. if (string.IsNullOrEmpty(_wechatOptions.WxOpenAppId) || string.IsNullOrEmpty(_wechatOptions.WxOpenAppSecret)) return;
  143. var req = new CgibinOpenApiQuotaGetRequest
  144. {
  145. AccessToken = await TryGetWxOpenAccessTokenAsync(),
  146. CgiPath = "/cgi-bin/token"
  147. };
  148. var client = CreateWxOpenClient();
  149. var res = await client.ExecuteCgibinOpenApiQuotaGetAsync(req);
  150. var originColor = Console.ForegroundColor;
  151. if (res.ErrorCode != (int)WechatReturnCodeEnum.请求成功)
  152. {
  153. _sysCacheService.Remove($"WxAccessToken_{_wechatOptions.WxOpenAppId}");
  154. Console.ForegroundColor = ConsoleColor.Red;
  155. Console.WriteLine("【" + DateTime.Now + "】" + _wechatOptions.WxOpenAppId + " 微信小程序令牌 无效");
  156. }
  157. else
  158. {
  159. Console.ForegroundColor = ConsoleColor.Magenta;
  160. Console.WriteLine("【" + DateTime.Now + "】" + _wechatOptions.WxOpenAppId + " 微信小程序令牌 有效");
  161. }
  162. Console.ForegroundColor = originColor;
  163. }
  164. /// <summary>
  165. /// 获取微信JS接口临时票据jsapi_ticket
  166. /// </summary>
  167. /// <returns></returns>
  168. public async Task<string> TryGetWechatJsApiTicketAsync()
  169. {
  170. if (!_sysCacheService.ExistKey($"WxJsApiTicket_{_wechatOptions.WechatAppId}") || string.IsNullOrEmpty(_sysCacheService.Get<string>($"WxJsApiTicket_{_wechatOptions.WechatAppId}")))
  171. {
  172. var accessToken = await TryGetWechatAccessTokenAsync();
  173. var client = CreateWechatClient();
  174. var request = new CgibinTicketGetTicketRequest()
  175. {
  176. AccessToken = accessToken
  177. };
  178. var response = await client.ExecuteCgibinTicketGetTicketAsync(request);
  179. if (!response.IsSuccessful())
  180. throw Oops.Oh(response.ErrorMessage + " " + response.ErrorCode);
  181. _sysCacheService.Set($"WxJsApiTicket_{_wechatOptions.WechatAppId}", response.Ticket, TimeSpan.FromSeconds(response.ExpiresIn - 60));
  182. }
  183. return _sysCacheService.Get<string>($"WxJsApiTicket_{_wechatOptions.WechatAppId}");
  184. }
  185. }