This commit is contained in:
CortexCore
2024-07-29 16:14:23 +08:00
parent c6b591ede9
commit d291923276
36 changed files with 361 additions and 173 deletions

View File

@@ -0,0 +1,66 @@
using System.Timers;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Timer = System.Timers.Timer;
namespace WeChatSharp.Services;
public class WeChatAccessTokenService
{
public const string _AccessToken = "access_token";
private readonly HttpClient _httpClient;
private readonly IWeChatSettings _weChatSettings;
private readonly Timer _timer=new();
private readonly ILogger<WeChatAccessTokenService> _logger;
private string AccessToken { get; set; }=string.Empty;
public WeChatAccessTokenService(HttpClient httpClient, IWeChatSettings weChatSettings, ILogger<WeChatAccessTokenService> logger)
{
_httpClient = httpClient;
_weChatSettings = weChatSettings;
_logger = logger;
_timer.AutoReset = true;
_timer.Interval = 3600 * 1000;
_timer.Elapsed+=_GetAccessToken;
}
private async void _GetAccessToken(object? sender, ElapsedEventArgs? e)
{
AccessToken = await GetAccessTokenAsync();
}
public async Task<string> GetAccessTokenAsync()
{
var newAccessToken = AccessToken;
if (!string.IsNullOrEmpty(newAccessToken)) return newAccessToken;
var url =
$"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={_weChatSettings.AppId}&secret={_weChatSettings.AppSecret}&token={_weChatSettings.Token}";
var json = await _httpClient.GetStringAsync(url);
var jObject = JsonConvert.DeserializeObject<JObject>(json);
if (jObject is null)
{
_logger.LogWarning(json);
throw new NullReferenceException("json为空值");
}
if (jObject.TryGetValue("errcode", out var errcode) && jObject.TryGetValue("errmsg",out var errmsg))
{
switch (errcode.ToObject<int>())
{
case 40164:
_logger.LogWarning("调用接口的IP地址不在白名单中请在接口IP白名单中进行设置。");
break;
}
throw new Exception(errmsg.ToObject<string>());
}
if (jObject.TryGetValue("access_token", out var token))
{
return newAccessToken = token.ToObject<string>() ?? string.Empty;
}
_logger.LogWarning(json);
throw new InvalidOperationException("获取AccessToken失败")
{
Source = json,
};
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 74ea767399428324097e7dbab4f35698
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
using System.Text;
using Newtonsoft.Json;
namespace WeChatSharp.Services;
public class WeChatHttpClient
{
private readonly WeChatAccessTokenService _accessTokenService;
private readonly HttpClient _httpClient;
public WeChatHttpClient(WeChatAccessTokenService accessTokenService, HttpClient httpClient)
{
_accessTokenService = accessTokenService;
_httpClient = httpClient;
}
public async Task<string> PostJsonAsync<T>(string url,T model)
{
var json = JsonConvert.SerializeObject(model);
var jsonContent = new StringContent(json, Encoding.UTF8, "application/json");
return await PostAsync(url, jsonContent);
}
public async Task<string> PostAsync(string url,HttpContent content)
{
url += $"?{WeChatAccessTokenService._AccessToken}={await _accessTokenService.GetAccessTokenAsync()}";
var responseMessage = await _httpClient.PostAsync(url, content);
return await responseMessage.Content.ReadAsStringAsync();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5abd85a5465eed24da3a7589d0fe017b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,81 @@
using Cysharp.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace WeChatSharp.Services;
public class WeChatMobileService
{
private readonly ILogger<WeChatMobileService> _logger;
public string AppId { get; set; } = string.Empty;
public string AppSecret { get; set; } = string.Empty;
private readonly HttpClient _httpClient=new();
public WeChatMobileService(ILogger<WeChatMobileService> logger)
{
_logger = logger;
}
public async UniTask<WeChatUserInfo> GetUserInfoAsync(string code,string openId)
{
var uri = new UriBuilder("https://api.weixin.qq.com/sns/userinfo")
{
Query = $"access_token={code}&openid={code}"
};
_logger.LogInformation($"请求地址:{uri.Uri}");
var response = await _httpClient.GetAsync(uri.Uri);
var json = await response.Content.ReadAsStringAsync();
var jObject = JsonConvert.DeserializeObject<JObject>(json);
if (jObject is null)
{
throw new NullReferenceException("json为空值");
}
if (jObject.TryGetValue("errcode", out var errcode) && jObject.TryGetValue("errmsg", out var errmsg))
{
throw new Exception(errmsg.ToObject<string>());
}
if (!jObject.TryGetValue("openid", out var openid))
throw new InvalidOperationException("获取OpenId失败")
{
Source = json
};
_logger.LogInformation($"获取OpenId成功:{openid.ToObject<string>()}");
return jObject.ToObject<WeChatUserInfo>() ?? new WeChatUserInfo();
}
public async UniTask<WeChatAccessToken> GetAccessCodeAsync(string code)
{
var uri = new UriBuilder("https://api.weixin.qq.com/sns/oauth2/access_token")
{
Query = $"appid={AppId}&secret={AppSecret}&code={code}&grant_type=authorization_code"
};
var response = await _httpClient.GetAsync(uri.Uri);
var json = await response.Content.ReadAsStringAsync();
var jObject = JsonConvert.DeserializeObject<JObject>(json);
if (jObject is null)
{
throw new NullReferenceException("json为空值");
}
if (jObject.TryGetValue("errcode", out var errcode) && jObject.TryGetValue("errmsg", out var errmsg))
{
throw new Exception(errmsg.ToObject<string>());
}
if (!jObject.TryGetValue("access_token", out var token))
throw new InvalidOperationException("获取AccessToken失败")
{
Source = json
};
_logger.LogInformation($"获取AccessToken成功:{token.ToObject<string>()}");
return jObject.ToObject<WeChatAccessToken>() ?? new WeChatAccessToken();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8a90d347df361134faa0c154b467723e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,22 @@
using Microsoft.Extensions.Configuration;
namespace WeChatSharp.Services;
public interface IWeChatSettings
{
public string AppId { get; }
public string AppSecret { get; }
public string Token { get; }
}
public class WeChatSettingsService:IWeChatSettings
{
public string AppId { get;private set; }
public string AppSecret { get;private set; }
public string Token { get; private set; }
public WeChatSettingsService(IConfiguration configuration)
{
AppId = configuration["WeChat:AppId"];
AppSecret = configuration["WeChat:AppSecret"];
Token = configuration["WeChat:Token"];
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0d4b3b16602b9484fbd4aef30d2ed627
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,102 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Numerics;
using Cysharp.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace WeChatSharp.Services;
public class WeChatUserInfoService
{
private readonly HttpClient _httpClient;
private readonly WeChatAccessTokenService accessTokenService;
private readonly IWeChatSettings _weChatSettings;
private readonly ILogger<WeChatUserInfoService> _logger;
private readonly ConcurrentDictionary<string,WeChatUserInfo> weChatUserInfos = new();
private readonly ConcurrentDictionary<string,WeChatUserInfo> codeBasedWeChatUserInfos = new();
public WeChatUserInfoService(HttpClient httpClient, WeChatAccessTokenService accessTokenService, IWeChatSettings weChatSettings, ILogger<WeChatUserInfoService> logger)
{
_httpClient = httpClient;
this.accessTokenService = accessTokenService;
_weChatSettings = weChatSettings;
_logger = logger;
}
public List<WeChatUserInfo> GetCachedWeChatUserInfos()
{
return weChatUserInfos.Values.ToList();
}
public async Task<WeChatUserInfo> GetUserInfoByCode(string code)
{
if (codeBasedWeChatUserInfos.TryGetValue(code, out var userInfo))
return userInfo;
var json = await _httpClient.GetStringAsync(
$"""
https://api.weixin.qq.com/sns/oauth2/access_token?appid={_weChatSettings.AppId}&secret={_weChatSettings.AppSecret}&code={code}&grant_type=authorization_code
""");
var jObject = JsonConvert.DeserializeObject<JObject>(json)!;
if (jObject.TryGetValue("errcode", out var value))
{
var ErrorMessage = jObject["errmsg"]!.ToObject<string>();
if (codeBasedWeChatUserInfos.TryGetValue(code, out userInfo))
{
return userInfo;
}
throw new InvalidOperationException(ErrorMessage);
}
if (jObject.TryGetValue("openid", out var _token) && jObject.TryGetValue("access_token",out var accessToken))
{
var openId = _token.ToObject<string>()!;
userInfo = await GetUserInfoAsync(openId,accessToken.ToObject<string>()!);
_logger.LogInformation($"已经获取到了{code}的用户:{userInfo.OpenId}");;
_logger.LogInformation(json);
codeBasedWeChatUserInfos.TryAdd(code, userInfo);
return userInfo;
}
_logger.LogWarning("没有找到OpenId,获取的数据为;");
_logger.LogWarning(json);
throw new InvalidOperationException("无效的Code");
}
public async Task<WeChatUserInfo> GetUserInfoAsync(string openId,string accessToken=default!)
{
if(weChatUserInfos.TryGetValue(openId,out var userInfo))
return userInfo;
userInfo =await GetWeChatUserInfoFromServer(openId,accessToken);
weChatUserInfos.TryAdd(openId,userInfo);
return userInfo;
}
private async Task<WeChatUserInfo> GetWeChatUserInfoFromServer(string openId,string _accessToken=default!)
{
var accessToken = _accessToken;
string url;
if (string.IsNullOrEmpty(accessToken))
{
accessToken = await accessTokenService.GetAccessTokenAsync();
url = $"https://api.weixin.qq.com/cgi-bin/user/info?access_token={accessToken}&openid={openId}&lang=zh_CN";
}
else
{
url = $"https://api.weixin.qq.com/sns/userinfo?access_token={accessToken}&openid={openId}&lang=zh_CN";
}
var json = await _httpClient.GetStringAsync(url);
var jObject = JsonConvert.DeserializeObject<JObject>(json)!;
if (jObject.ContainsKey("errcode"))
{
Console.WriteLine(jObject);
}
var weChatUserInfo = JsonConvert.DeserializeObject<WeChatUserInfo>(json);
return weChatUserInfo;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0d3fadf37baa969479b11a2b4fa504be
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: