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;
}
}
}