diff --git a/Yi.Abp.Net8/Yi.Abp.sln b/Yi.Abp.Net8/Yi.Abp.sln
index 0068eabd..6ad08a47 100644
--- a/Yi.Abp.Net8/Yi.Abp.sln
+++ b/Yi.Abp.Net8/Yi.Abp.sln
@@ -182,6 +182,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollect
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.DigitalCollectibles.SqlSugarCore", "module\digital-collectibles\Yi.Framework.DigitalCollectibles.SqlSugarCore\Yi.Framework.DigitalCollectibles.SqlSugarCore.csproj", "{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yi.Framework.WeChat.MiniProgram", "framework\Yi.Framework.WeChat.MiniProgram\Yi.Framework.WeChat.MiniProgram.csproj", "{81CEA2ED-917B-41D8-BE0D-39A785B050C0}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -460,6 +462,10 @@ Global
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {81CEA2ED-917B-41D8-BE0D-39A785B050C0}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -541,6 +547,7 @@ Global
{9B5CAE1A-E062-4C9B-8121-E58FBF69309C} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
{FFEC9DA6-1A13-480A-AE9E-2BF8763D3061} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
{4CE6E4AE-0BA4-4984-A4F1-A9A414B1BB8F} = {B8F76A6B-2EEB-4E64-9F26-D84584E16B9C}
+ {81CEA2ED-917B-41D8-BE0D-39A785B050C0} = {77B949E9-530E-45A5-9657-20F7D5C6875C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {23D6FBC9-C970-4641-BC1E-2AEA59F51C18}
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Abstract/IErrorObjct.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Abstract/IErrorObjct.cs
new file mode 100644
index 00000000..4fd9de89
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Abstract/IErrorObjct.cs
@@ -0,0 +1,6 @@
+namespace Yi.Framework.WeChat.MiniProgram.Abstract;
+
+public interface IErrorObjct: IHasErrcode, IHasErrmsg
+{
+
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Abstract/IHasErrcode.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Abstract/IHasErrcode.cs
new file mode 100644
index 00000000..d4d77967
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Abstract/IHasErrcode.cs
@@ -0,0 +1,6 @@
+namespace Yi.Framework.WeChat.MiniProgram.Abstract;
+
+public interface IHasErrcode
+{
+ public int errcode { get; set; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Abstract/IHasErrmsg.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Abstract/IHasErrmsg.cs
new file mode 100644
index 00000000..e742d220
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Abstract/IHasErrmsg.cs
@@ -0,0 +1,6 @@
+namespace Yi.Framework.WeChat.MiniProgram.Abstract;
+
+public interface IHasErrmsg
+{
+ string errmsg { get; set; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/HttpModels/AccessTokenHttpModel.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/HttpModels/AccessTokenHttpModel.cs
new file mode 100644
index 00000000..380a55e5
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/HttpModels/AccessTokenHttpModel.cs
@@ -0,0 +1,15 @@
+namespace Yi.Framework.WeChat.MiniProgram.HttpModels;
+
+public class AccessTokenResponse
+{
+ public string access_token { get; set; }
+
+ public int expires_in { get; set; }
+}
+
+public class AccessTokenRequest
+{
+ public string grant_type { get; set; }
+ public string appid { get; set; }
+ public string secret { get; set; }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/HttpModels/Code2SessionHttpModel.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/HttpModels/Code2SessionHttpModel.cs
new file mode 100644
index 00000000..90a2de37
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/HttpModels/Code2SessionHttpModel.cs
@@ -0,0 +1,31 @@
+using Yi.Framework.WeChat.MiniProgram.Abstract;
+
+namespace Yi.Framework.WeChat.MiniProgram.HttpModels;
+
+
+ public class Code2SessionResponse: IErrorObjct
+ {
+ public string openid { get; set; }
+ public string session_key { get; set; }
+ public string unionid { get; set; }
+ public int errcode { get; set; }
+ public string errmsg { get; set; }
+ }
+
+ public class Code2SessionRequest
+ {
+ public string appid { get; set; }
+ public string secret { get; set; }
+ public string js_code { get; set; }
+ public string grant_type => "authorization_code";
+ }
+
+ public class Code2SessionInput
+ {
+ public Code2SessionInput(string js_code)
+ {
+
+ this.js_code=js_code;
+ }
+ public string js_code { get; set; }
+ }
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/IWeChatMiniProgramManager.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/IWeChatMiniProgramManager.cs
new file mode 100644
index 00000000..3c6d55aa
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/IWeChatMiniProgramManager.cs
@@ -0,0 +1,13 @@
+using Yi.Framework.WeChat.MiniProgram.HttpModels;
+
+namespace Yi.Framework.WeChat.MiniProgram;
+
+public interface IWeChatMiniProgramManager
+{
+ ///
+ /// 获取用户openid
+ ///
+ ///
+ ///
+ Task Code2SessionAsync(Code2SessionInput input);
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Token/CacheMiniProgramToken.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Token/CacheMiniProgramToken.cs
new file mode 100644
index 00000000..d88ac791
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Token/CacheMiniProgramToken.cs
@@ -0,0 +1,28 @@
+using Microsoft.Extensions.Caching.Distributed;
+using Microsoft.Extensions.Options;
+using Volo.Abp.Caching;
+
+namespace Yi.Framework.WeChat.MiniProgram.Token;
+
+internal class CacheMiniProgramToken : DefaultMinProgramToken, IMiniProgramToken
+{
+ private IDistributedCache _cache;
+ private const string CacheKey = "MiniProgramToken";
+
+ public CacheMiniProgramToken(IOptions options, IDistributedCache cache) :
+ base(options)
+ {
+ _cache = cache;
+ }
+
+ public async Task GetTokenAsync()
+ {
+ return await _cache.GetOrAddAsync("MiniProgramToken", async () => { return await base.GetTokenAsync(); }, () =>
+ {
+ return new DistributedCacheEntryOptions()
+ {
+ AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(2) - TimeSpan.FromMinutes(1)
+ };
+ });
+ }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Token/DefaultMinProgramToken.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Token/DefaultMinProgramToken.cs
new file mode 100644
index 00000000..36d1635a
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Token/DefaultMinProgramToken.cs
@@ -0,0 +1,40 @@
+using System.Net.Http.Json;
+using Microsoft.Extensions.Options;
+using Yi.Framework.Core.Extensions;
+using Yi.Framework.WeChat.MiniProgram.HttpModels;
+
+namespace Yi.Framework.WeChat.MiniProgram.Token;
+
+internal class DefaultMinProgramToken:IMiniProgramToken
+{
+ private const string Url = "https://api.weixin.qq.com/cgi-bin/token";
+ private WeChatMiniProgramOptions _options;
+ public DefaultMinProgramToken(IOptions options)
+ {
+ _options = options.Value;
+ }
+ public async Task GetTokenAsync()
+ {
+ var token = await this.GetAccessToken();
+ return token.access_token;
+ }
+ public async Task GetAccessToken()
+ {
+ var req = new AccessTokenRequest();
+ req.appid = _options.AppID;
+ req.secret = _options.AppSecret;
+ req.grant_type = "client_credential";
+ using (HttpClient httpClient = new HttpClient())
+ {
+ string queryString = req.ToQueryString();
+ var builder = new UriBuilder(Url);
+ builder.Query = queryString;
+ HttpResponseMessage response = await httpClient.GetAsync(builder.ToString());
+
+ response.EnsureSuccessStatusCode();
+
+ var responseBody = await response.Content.ReadFromJsonAsync();
+ return responseBody;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Token/IMiniProgramToken.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Token/IMiniProgramToken.cs
new file mode 100644
index 00000000..45ab9f02
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/Token/IMiniProgramToken.cs
@@ -0,0 +1,6 @@
+namespace Yi.Framework.WeChat.MiniProgram.Token;
+
+public interface IMiniProgramToken
+{
+ public Task GetTokenAsync();
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/WeChatMiniProgramException.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/WeChatMiniProgramException.cs
new file mode 100644
index 00000000..327edbca
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/WeChatMiniProgramException.cs
@@ -0,0 +1,27 @@
+namespace Yi.Framework.WeChat.MiniProgram;
+
+public class WeChatMiniProgramException: Exception
+{
+ public override string Message
+ {
+ get
+ {
+ // 加上前缀
+ return "微信Api异常: " + base.Message;
+ }
+ }
+
+ public WeChatMiniProgramException()
+ {
+ }
+
+ public WeChatMiniProgramException(string message)
+ : base(message)
+ {
+ }
+
+ public WeChatMiniProgramException(string message, Exception innerException)
+ : base(message, innerException)
+ {
+ }
+}
\ No newline at end of file
diff --git a/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/WeChatMiniProgramExtensions.cs b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/WeChatMiniProgramExtensions.cs
new file mode 100644
index 00000000..1642e22b
--- /dev/null
+++ b/Yi.Abp.Net8/framework/Yi.Framework.WeChat.MiniProgram/WeChatMiniProgramExtensions.cs
@@ -0,0 +1,50 @@
+using System.Reflection;
+using System.Web;
+using Yi.Framework.WeChat.MiniProgram.Abstract;
+
+namespace Yi.Framework.WeChat.MiniProgram;
+
+public static class WeChatMiniProgramExtensions
+{
+ ///
+ /// 效验请求是否成功
+ ///
+ ///
+ ///
+ internal static void ValidateSuccess(this IErrorObjct response)
+ {
+
+ if (response.errcode != 0)
+ {
+ throw new WeChatMiniProgramException(response.errmsg);
+ }
+ }
+
+ internal static string ToQueryString(this T obj)
+ {
+ var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
+ var queryParams = new List();
+
+ foreach (var prop in properties)
+ {
+ var value = prop.GetValue(obj, null);
+ if (value != null)
+ {
+ // 处理集合
+ if (value is IEnumerable