1
This commit is contained in:
8
Src/Commands.meta
Normal file
8
Src/Commands.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cadc6681b7ee58e4e8ae57a4784a25b9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
22
Src/Commands/OnReceiveWeChatMessage.cs
Normal file
22
Src/Commands/OnReceiveWeChatMessage.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace WeChatSharp.Commands;
|
||||
|
||||
public interface IReceiveWeChatMessage
|
||||
{
|
||||
string OpenId { get; }
|
||||
string UserName { get; }
|
||||
WeChatUserInfo UserInfo { get; }
|
||||
string Context { get; }
|
||||
}
|
||||
public readonly struct OnReceiveWeChatMessage:IReceiveWeChatMessage
|
||||
{
|
||||
public string OpenId => UserInfo.OpenId;
|
||||
|
||||
public string UserName => UserInfo switch
|
||||
{
|
||||
var x when string.IsNullOrEmpty(x.NickName) is false=>x.NickName,
|
||||
var x when string.IsNullOrEmpty(x.Remark) is false=>x.Remark,
|
||||
_ => OpenId,
|
||||
};
|
||||
public WeChatUserInfo UserInfo { get; init; }
|
||||
public string Context { get; init; }
|
||||
}
|
11
Src/Commands/OnReceiveWeChatMessage.cs.meta
Normal file
11
Src/Commands/OnReceiveWeChatMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c7fbd0297b3ffa4290de1be763c6960
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Src/Extensions.meta
Normal file
8
Src/Extensions.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb08a656d9668574389decbedbec6ce2
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
17
Src/Extensions/WeChatExtensions.cs
Normal file
17
Src/Extensions/WeChatExtensions.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using WeChatSharp.Services;
|
||||
|
||||
namespace WeChatSharp.Extensions;
|
||||
|
||||
public static class WeChatExtensions
|
||||
{
|
||||
public static IServiceCollection AddWeChatService(this IServiceCollection self)
|
||||
{
|
||||
self.AddSingleton<WeChatAccessTokenService>();
|
||||
self.AddSingleton<WeChatUserInfoService>();
|
||||
self.AddSingleton<IWeChatSettings,WeChatSettingsService>();
|
||||
self.AddSingleton<WeChatHttpClient>();
|
||||
return self;
|
||||
}
|
||||
}
|
11
Src/Extensions/WeChatExtensions.cs.meta
Normal file
11
Src/Extensions/WeChatExtensions.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c271aafe92f01547bb4f1f4f411f935
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Src/Models.meta
Normal file
8
Src/Models.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 685f9f54d2f0ccb4da01908178cf26b0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Src/Models/TemplateMessage.meta
Normal file
8
Src/Models/TemplateMessage.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 306d4bda8b5dfee41b36437cf4684383
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
41
Src/Models/TemplateMessage/IWeChatTemplateMessage.cs
Normal file
41
Src/Models/TemplateMessage/IWeChatTemplateMessage.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace WeChatSharp
|
||||
{
|
||||
/// <summary>
|
||||
/// 微信模板消息接口定义
|
||||
/// </summary>
|
||||
public interface IWeChatTemplateMessage
|
||||
{
|
||||
/// <summary>
|
||||
/// 接收者(用户)的 openid
|
||||
/// </summary>
|
||||
[JsonProperty("touser")]
|
||||
string ToUser { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板Id
|
||||
/// </summary>
|
||||
[JsonProperty("template_id")]
|
||||
string TemplateId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息的Url
|
||||
/// </summary>
|
||||
[JsonProperty("url")]
|
||||
string Url { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 消息的id,通常为Guid.New
|
||||
/// </summary>
|
||||
[JsonProperty("client_msg_id")]
|
||||
string ClientMsgId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 模板消息的数据
|
||||
/// </summary>
|
||||
[JsonProperty("data")]
|
||||
IDictionary<string, WeChatTemplateMessageData> Data { get; }
|
||||
}
|
||||
}
|
11
Src/Models/TemplateMessage/IWeChatTemplateMessage.cs.meta
Normal file
11
Src/Models/TemplateMessage/IWeChatTemplateMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3818fa8c896531a489272a81e6f04e78
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
25
Src/Models/WeChatAccessToken.cs
Normal file
25
Src/Models/WeChatAccessToken.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace WeChatSharp
|
||||
{
|
||||
public class WeChatAccessToken
|
||||
{
|
||||
[JsonProperty("access_token")]
|
||||
public string AccessToken { get; set; }
|
||||
|
||||
[JsonProperty("expires_in")]
|
||||
public int ExpiresIn { get; set; }
|
||||
|
||||
[JsonProperty("refresh_token")]
|
||||
public string RefreshToken { get; set; }
|
||||
|
||||
[JsonProperty("openid")]
|
||||
public string OpenId { get; set; }
|
||||
|
||||
[JsonProperty("scope")]
|
||||
public string Scope { get; set; }
|
||||
|
||||
[JsonProperty("unionid")]
|
||||
public string UnionId { get; set; }
|
||||
}
|
||||
}
|
11
Src/Models/WeChatAccessToken.cs.meta
Normal file
11
Src/Models/WeChatAccessToken.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f93beebe428073d47b08c001d80749bd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
14
Src/Models/WeChatSharp.asmdef
Normal file
14
Src/Models/WeChatSharp.asmdef
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "WeChatSharp",
|
||||
"rootNamespace": "",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": true
|
||||
}
|
7
Src/Models/WeChatSharp.asmdef.meta
Normal file
7
Src/Models/WeChatSharp.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ff759f134ec63c408c65b69f8fa11a7
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
49
Src/Models/WeChatTemplateMessage.cs
Normal file
49
Src/Models/WeChatTemplateMessage.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace WeChatSharp
|
||||
{
|
||||
|
||||
public struct WeChatTemplateMessageData
|
||||
{
|
||||
public WeChatTemplateMessageData(string value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 值
|
||||
/// </summary>
|
||||
public string value { get; set; }
|
||||
}
|
||||
|
||||
public struct WeChatTemplateMessage : IWeChatTemplateMessage
|
||||
{
|
||||
[JsonProperty("touser")] public string ToUser { get; set; }
|
||||
[JsonProperty("template_id")] public string TemplateId { get; set; }
|
||||
[JsonProperty("url")] public string Url { get; set; }
|
||||
[JsonProperty("client_msg_id")] public string ClientMsgId { get; set; }
|
||||
[JsonProperty("data")] public IDictionary<string, WeChatTemplateMessageData> Data { get; set; }
|
||||
}
|
||||
// {
|
||||
// "touser":"oY0tZ6_aqq_MEWsej9zJEY6OVspI",
|
||||
// "template_id":"TA6ogf8kMiB31M0oQ8WCxteITUauajrtuGL1LtptNg0",
|
||||
// "url":"http://weixin.qq.com/download",
|
||||
// "client_msg_id":"MSG_000002",
|
||||
// "data":{
|
||||
//
|
||||
// "character_string5":{
|
||||
// "value":"202307251515"
|
||||
// },
|
||||
// "thing4": {
|
||||
// "value":"已创建"
|
||||
// },
|
||||
// "thing9": {
|
||||
// "value":"CAICT"
|
||||
// },
|
||||
// "phrase13":{
|
||||
// "value":"手动提交"
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
11
Src/Models/WeChatTemplateMessage.cs.meta
Normal file
11
Src/Models/WeChatTemplateMessage.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d3b667edd95b85458a29992a4f3acd0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
74
Src/Models/WeChatUserInfo.cs
Normal file
74
Src/Models/WeChatUserInfo.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace WeChatSharp
|
||||
{
|
||||
|
||||
[Serializable]
|
||||
public record WeChatUserInfo
|
||||
{
|
||||
[JsonProperty(propertyName: "subscribe")]
|
||||
public int Subscribe;
|
||||
|
||||
[JsonProperty(propertyName: "openid")] public string OpenId;
|
||||
|
||||
[JsonProperty(propertyName: "nickname")]
|
||||
public string NickName;
|
||||
|
||||
[JsonProperty(propertyName: "sex")] public int Sex;
|
||||
|
||||
[JsonProperty(propertyName: "language")]
|
||||
public string Language;
|
||||
|
||||
[JsonProperty(propertyName: "city")] public string City;
|
||||
|
||||
[JsonProperty(propertyName: "province")]
|
||||
public string Province;
|
||||
|
||||
[JsonProperty(propertyName: "country")]
|
||||
public string Country;
|
||||
|
||||
[JsonProperty(propertyName: "headimgurl")]
|
||||
public string HeadImgUrl;
|
||||
|
||||
[JsonProperty(propertyName: "subscribe_time")]
|
||||
public int SubscribeTime;
|
||||
|
||||
[JsonProperty(propertyName: "remark")] public string Remark;
|
||||
|
||||
[JsonProperty(propertyName: "groupid")]
|
||||
public int GroupId;
|
||||
|
||||
[JsonProperty(propertyName: "tagid_list")]
|
||||
public string[] TagIdList;
|
||||
|
||||
[JsonProperty(propertyName: "subscribe_scene")]
|
||||
public string SubscribeScene;
|
||||
|
||||
[JsonProperty(propertyName: "qr_scene")]
|
||||
public int QrScene;
|
||||
|
||||
[JsonProperty(propertyName: "qr_scene_str")]
|
||||
public string QrSceneStr;
|
||||
}
|
||||
/*
|
||||
{
|
||||
"subscribe": 1,
|
||||
"openid": "oY0tZ6_aqq_MEWsej9zJEY6OVspI",
|
||||
"nickname": "",
|
||||
"sex": 0,
|
||||
"language": "zh_CN",
|
||||
"city": "",
|
||||
"province": "",
|
||||
"country": "",
|
||||
"headimgurl": "",
|
||||
"subscribe_time": 1687668622,
|
||||
"remark": "Root",
|
||||
"groupid": 0,
|
||||
"tagid_list": [],
|
||||
"subscribe_scene": "ADD_SCENE_SEARCH",
|
||||
"qr_scene": 0,
|
||||
"qr_scene_str": ""
|
||||
}
|
||||
*/
|
||||
}
|
11
Src/Models/WeChatUserInfo.cs.meta
Normal file
11
Src/Models/WeChatUserInfo.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c6408b8b167de0418a4f9a642fb492c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Src/Services.meta
Normal file
8
Src/Services.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a97aa7f0cdbf9948a0916f82f7a755f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
66
Src/Services/WeChatAccessTokenService.cs
Normal file
66
Src/Services/WeChatAccessTokenService.cs
Normal 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,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
11
Src/Services/WeChatAccessTokenService.cs.meta
Normal file
11
Src/Services/WeChatAccessTokenService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 74ea767399428324097e7dbab4f35698
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
28
Src/Services/WeChatHttpClient.cs
Normal file
28
Src/Services/WeChatHttpClient.cs
Normal 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();
|
||||
}
|
||||
}
|
11
Src/Services/WeChatHttpClient.cs.meta
Normal file
11
Src/Services/WeChatHttpClient.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5abd85a5465eed24da3a7589d0fe017b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
81
Src/Services/WeChatMobileService.cs
Normal file
81
Src/Services/WeChatMobileService.cs
Normal 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();
|
||||
}
|
||||
}
|
11
Src/Services/WeChatMobileService.cs.meta
Normal file
11
Src/Services/WeChatMobileService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a90d347df361134faa0c154b467723e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
22
Src/Services/WeChatSettingsService.cs
Normal file
22
Src/Services/WeChatSettingsService.cs
Normal 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"];
|
||||
}
|
||||
}
|
11
Src/Services/WeChatSettingsService.cs.meta
Normal file
11
Src/Services/WeChatSettingsService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d4b3b16602b9484fbd4aef30d2ed627
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
102
Src/Services/WeChatUserInfoService.cs
Normal file
102
Src/Services/WeChatUserInfoService.cs
Normal 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;
|
||||
}
|
||||
}
|
11
Src/Services/WeChatUserInfoService.cs.meta
Normal file
11
Src/Services/WeChatUserInfoService.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d3fadf37baa969479b11a2b4fa504be
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Src/package.json
Normal file
8
Src/package.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "com.bitkit.wechat",
|
||||
"displayName": "WeChatSharp",
|
||||
"version": "2024.3.31",
|
||||
"unity": "2022.3",
|
||||
"description": "WeChat,微信SDK支持",
|
||||
"dependencies": {}
|
||||
}
|
7
Src/package.json.meta
Normal file
7
Src/package.json.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7eed4d66378d235449ef9c609e45a102
|
||||
PackageManifestImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user