zhengyiming
3 天以前 b8cf451145b72ff7ce728c101adad3574e722697
FlexJobApi.Core/Utils/WxmpUtils/WxmpUtils.cs
@@ -1,10 +1,19 @@
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;
@@ -17,23 +26,26 @@
    {
        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 },
@@ -45,5 +57,72 @@
                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;
        }
    }
}