| | |
| | | using Furion.FriendlyException; |
| | | using Aliyun.OSS; |
| | | using Azure.Core; |
| | | using FlexJobApi.Core.Utils.WxmpUtils; |
| | | using Furion.FriendlyException; |
| | | using Furion.HttpRemote; |
| | | using Mapster; |
| | | using Microsoft.Extensions.Caching.Distributed; |
| | | using Microsoft.Extensions.Options; |
| | | using Newtonsoft.Json; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.IO; |
| | | using System.Linq; |
| | | using System.Net.Http.Json; |
| | | using System.Text; |
| | | using System.Text.Json.Nodes; |
| | | using System.Threading; |
| | | using System.Threading.Tasks; |
| | | |
| | |
| | | { |
| | | private readonly IOptions<WxmpOptions> options; |
| | | private readonly IHttpRemoteService httpRemoteService; |
| | | private readonly IDistributedCache distributedCache; |
| | | |
| | | public WxmpUtils( |
| | | IOptions<WxmpOptions> options, |
| | | IHttpRemoteService httpRemoteService) |
| | | IHttpRemoteService httpRemoteService, |
| | | IDistributedCache distributedCache) |
| | | { |
| | | this.options = options; |
| | | this.httpRemoteService = httpRemoteService; |
| | | this.distributedCache = distributedCache; |
| | | } |
| | | |
| | | public async Task<WxmpSnsJscode2sessionCallback> SnsJscode2sessionAsync(EnumUserType userType, string code, CancellationToken cancellationToken = default) |
| | | public async Task<WxmpSnsJscode2sessionResponse> SnsJscode2sessionAsync(EnumUserType userType, string code, CancellationToken cancellationToken = default) |
| | | { |
| | | var option = options.Value.Items.FirstOrDefault(it => it.Code == userType.ToString()); |
| | | if (option == null || option.AppId.IsNull() || option.AppSecret.IsNull()) |
| | | throw Oops.Oh(EnumErrorCodeType.s400, "登录失败,缺失配置:WxmpOptions"); |
| | | if (code.IsNull()) |
| | | throw Oops.Oh(EnumErrorCodeType.s400, "请填写WxmpCode"); |
| | | var callback = await httpRemoteService.GetAsAsync<WxmpSnsJscode2sessionCallback>("https://api.weixin.qq.com/sns/jscode2session", |
| | | var callback = await httpRemoteService.GetAsAsync<WxmpSnsJscode2sessionResponse>("https://api.weixin.qq.com/sns/jscode2session", |
| | | builder => builder.WithQueryParameters(new Dictionary<string, string> |
| | | { |
| | | { "appid", option.AppId }, |
| | |
| | | throw Oops.Oh(EnumErrorCodeType.s510, $"登录失败:{callback.errmsg},请联系管理员"); |
| | | return callback; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取小程序接口调用凭据 |
| | | /// </summary> |
| | | /// <param name="userType"></param> |
| | | /// <returns></returns> |
| | | public async Task<string> GetAccessToken(EnumUserType userType) |
| | | { |
| | | var cacheKey = $"Wxmp|{userType}|AccessToken"; |
| | | var accessToken = await distributedCache.GetStringAsync(cacheKey); |
| | | if (accessToken.IsNull()) |
| | | { |
| | | var option = options.Value.Items.FirstOrDefault(it => it.Code == userType.ToString()); |
| | | if (option == null || option.AppId.IsNull() || option.AppSecret.IsNull()) |
| | | throw Oops.Oh(EnumErrorCodeType.s400, "获取小程序接口调用凭据失败,缺失配置:WxmpOptions"); |
| | | var request = new WxmpGetAccessTokenRequest |
| | | { |
| | | Appid = option.AppId, |
| | | Secret = option.AppSecret, |
| | | }; |
| | | var response = await httpRemoteService.GetAsStringAsync("https://api.weixin.qq.com/cgi-bin/token", |
| | | builder => builder.WithQueryParameters(JsonObject.Parse(request.ToJson()))); |
| | | var callback = response.JsonTo<WxmpGetAccessTokenResponse>(); |
| | | if (callback == null && callback.AccessToken.IsNull()) |
| | | throw Oops.Oh(EnumErrorCodeType.s510, "获取小程序接口调用凭据失败"); |
| | | accessToken = callback.AccessToken; |
| | | await distributedCache.SetStringAsync(cacheKey, accessToken, new DistributedCacheEntryOptions |
| | | { |
| | | AbsoluteExpirationRelativeToNow = TimeSpan.FromSeconds(callback.ExpiresIn - 300) |
| | | }); |
| | | } |
| | | return accessToken; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 获取小程序码 |
| | | /// </summary> |
| | | /// <param name="command"></param> |
| | | /// <returns></returns> |
| | | public async Task<string> GetQrCodeOssUrl(WxmpGetQrCodeCommand command) |
| | | { |
| | | var option = options.Value.Items.FirstOrDefault(it => it.Code == command.UserType.ToString()); |
| | | if (option == null || option.AppId.IsNull() || option.AppSecret.IsNull()) |
| | | throw Oops.Oh(EnumErrorCodeType.s400, "获取小程序码失败,缺失配置:WxmpOptions"); |
| | | command.EnvVersion = option.EnvVersion; |
| | | var accessToken = await GetAccessToken(command.UserType); |
| | | var request = command.Adapt<WxmpGetQrCodeRequest>(); |
| | | var jsonContent = JsonConvert.SerializeObject(request, new JsonSerializerSettings |
| | | { |
| | | NullValueHandling = NullValueHandling.Ignore |
| | | }); |
| | | var response = await httpRemoteService.PostAsync("https://api.weixin.qq.com/wxa/getwxacodeunlimit", |
| | | builder => builder |
| | | .WithQueryParameter("access_token", accessToken) |
| | | .SetJsonContent(jsonContent)); |
| | | response.EnsureSuccessStatusCode(); |
| | | if (response.Content.Headers.ContentType.ToString() == "application/json; charset=UTF-8") |
| | | { |
| | | var jsonResult = await response.Content.ReadAsStringAsync(); |
| | | var callback = jsonResult.JsonTo<WxmpGetQrCodeResponse>(); |
| | | if (callback == null || callback.ErrorCode != 0) |
| | | throw Oops.Oh(EnumErrorCodeType.s510, $"获取小程序码失败:{callback.ErrorMessage},请联系管理员"); |
| | | } |
| | | var stream = await response.Content.ReadAsStreamAsync(); |
| | | var result = AliyunOSSUtils.Upload(command.OssScene, stream, command.OssFileName); |
| | | return result.Url; |
| | | } |
| | | } |
| | | } |