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; namespace FlexJobApi.Core { /// /// 微信小程序工具 /// public class WxmpUtils { private readonly IOptions options; private readonly IHttpRemoteService httpRemoteService; private readonly IDistributedCache distributedCache; public WxmpUtils( IOptions options, IHttpRemoteService httpRemoteService, IDistributedCache distributedCache) { this.options = options; this.httpRemoteService = httpRemoteService; this.distributedCache = distributedCache; } public async Task 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("https://api.weixin.qq.com/sns/jscode2session", builder => builder.WithQueryParameters(new Dictionary { { "appid", option.AppId }, { "secret", option.AppSecret }, { "js_code", code }, { "grant_type", "authorization_code" } })); if (callback == null || callback.errcode != 0) throw Oops.Oh(EnumErrorCodeType.s510, $"登录失败:{callback.errmsg},请联系管理员"); return callback; } /// /// 获取小程序接口调用凭据 /// /// /// public async Task 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(); 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; } /// /// 获取小程序码 /// /// /// public async Task 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(); 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(); 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; } } }