😎1、修复角色权限修改时清空相关用户权限缓存 2、优化请求时仓库获取租户ID 3、升级依赖及其他优化调整

This commit is contained in:
zuohuaijun
2025-11-23 20:05:17 +08:00
parent 11fa5a028d
commit d3b864a2e8
24 changed files with 90 additions and 86 deletions

View File

@@ -39,22 +39,22 @@
},
// 自定义短信接口
"Custom": {
"Enabled": false, // 是否启用自定义短信接口
"Method": "GET", // 请求方法: GET 或 POST
"ApiUrl": "https://api.xxxx.com/sms?u=xxxx&key=59e03f49c3dbb5033&m={mobile}&c={content}", // API接口地址支持占位符: {mobile}, {content}, {code}
"ContentType": "application/x-www-form-urlencoded", // POST请求的Content-Type: application/json 或 application/x-www-form-urlencoded
"PostData": "", // POST请求的数据模板支持占位符JSON 格式示例: {"mobile":"{mobile}","content":"{content}","apikey":"your_key"}Form 格式示例: mobile={mobile}&content={content}&apikey=your_key
"SuccessFlag": "0", // 成功响应标识,响应内容包含此字符串则认为发送成功
"Templates": [
{
"Id": "0",
"Content": "您的验证码为:{code},请勿泄露于他人!"
},
{
"Id": "1",
"Content": "注册成功,感谢您的注册,请妥善保管您的账户信息"
}
]
"Enabled": false, // 是否启用自定义短信接口
"Method": "GET", // 请求方法: GET 或 POST
"ApiUrl": "https://api.xxxx.com/sms?u=xxxx&key=59e03f49c3dbb5033&m={mobile}&c={content}", // API接口地址支持占位符: {mobile}, {content}, {code}
"ContentType": "application/x-www-form-urlencoded", // POST请求的Content-Type: application/json 或 application/x-www-form-urlencoded
"PostData": "", // POST请求的数据模板支持占位符JSON 格式示例: {"mobile":"{mobile}","content":"{content}","apikey":"your_key"}Form 格式示例: mobile={mobile}&content={content}&apikey=your_key
"SuccessFlag": "0", // 成功响应标识,响应内容包含此字符串则认为发送成功
"Templates": [
{
"Id": "0",
"Content": "您的验证码为:{code},请勿泄露于他人!"
},
{
"Id": "1",
"Content": "注册成功,感谢您的注册,请妥善保管您的账户信息"
}
]
}
}
}

View File

@@ -19,9 +19,9 @@
<PackageReference Include="AspectCore.Extensions.Reflection" Version="2.4.0" />
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="Elastic.Clients.Elasticsearch" Version="9.2.1" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.208" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.208" />
<PackageReference Include="Furion.Pure" Version="4.9.7.208" />
<PackageReference Include="Furion.Extras.Authentication.JwtBearer" Version="4.9.7.211" />
<PackageReference Include="Furion.Extras.ObjectMapper.Mapster" Version="4.9.7.211" />
<PackageReference Include="Furion.Pure" Version="4.9.7.211" />
<PackageReference Include="Hardware.Info" Version="101.1.0.1" />
<PackageReference Include="Hashids.net" Version="1.7.0" />
<PackageReference Include="IPTools.China" Version="1.6.0" />
@@ -42,8 +42,8 @@
<PackageReference Include="SixLabors.ImageSharp.Web" Version="3.2.0" />
<PackageReference Include="SKIT.FlurlHttpClient.Wechat.Api" Version="3.12.0" />
<PackageReference Include="SKIT.FlurlHttpClient.Wechat.TenpayV3" Version="3.16.0" />
<PackageReference Include="SqlSugar.MongoDbCore" Version="5.1.4.271" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.207" />
<PackageReference Include="SqlSugar.MongoDbCore" Version="5.1.4.275" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.210" />
<PackageReference Include="SSH.NET" Version="2025.1.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.7.0" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1346" />

View File

@@ -44,4 +44,4 @@ public class ElasticSearchClientContainer
}
throw new KeyNotFoundException($"未注册的ES客户端类型{type},请检查注册配置");
}
}
}

View File

@@ -65,18 +65,21 @@ public class ElasticSearchClientFactory
case ElasticSearchAuthTypeEnum.Basic:
settings.Authentication(new BasicAuthentication(options.User, options.Password));
break;
case ElasticSearchAuthTypeEnum.ApiKey:
settings.Authentication(new ApiKey(options.ApiKey));
break;
case ElasticSearchAuthTypeEnum.Base64ApiKey:
settings.Authentication(new Base64ApiKey(options.Base64ApiKey));
break;
case ElasticSearchAuthTypeEnum.None:
// 无需认证
break;
default:
throw new ArgumentOutOfRangeException(nameof(options.AuthType));
}
}
}
}

View File

@@ -95,7 +95,7 @@ public abstract class EntityBaseDel : EntityBase, IDeletedFilter
/// 软删除时间
/// </summary>
[SugarColumn(ColumnDescription = "软删除时间")]
public virtual DateTime? DeleteTime { get; set; }
public virtual DateTime? DeleteTime { get; set; }
}
/// <summary>

View File

@@ -5,7 +5,6 @@
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Newtonsoft.Json;
using static Microsoft.ApplicationInsights.MetricDimensionNames.TelemetryContext;
namespace Admin.NET.Core;
@@ -33,7 +32,6 @@ public partial class SysFileProvider : EntityBaseTenant
[Required, MaxLength(32)]
public virtual string BucketName { get; set; }
/// <summary>
/// 访问密钥 (填入 阿里云Aliyun/Minio的 AccessKey腾讯云QCloud: 的 SecretId
/// </summary>
@@ -41,7 +39,6 @@ public partial class SysFileProvider : EntityBaseTenant
[MaxLength(128)]
public virtual string? AccessKey { get; set; }
/// <summary>
/// 密钥
/// </summary>
@@ -118,4 +115,4 @@ public partial class SysFileProvider : EntityBaseTenant
/// </summary>
[SugarColumn(IsIgnore = true)]
public virtual string ConfigKey => $"{Provider}_{BucketName}_{Id}";
}
}

View File

@@ -20,4 +20,4 @@ public enum EsClientTypeEnum
/// 业务数据
/// </summary>
Business
}
}

View File

@@ -102,8 +102,8 @@ public static class SqlSugarExtension
{
return filterLogic switch
{
FilterLogicEnum.And => Expression.And(bExpresionBase, bExpresion),
FilterLogicEnum.Or => Expression.Or(bExpresionBase, bExpresion),
FilterLogicEnum.And => Expression.AndAlso(bExpresionBase, bExpresion),
FilterLogicEnum.Or => Expression.OrElse(bExpresionBase, bExpresion),
FilterLogicEnum.Xor => Expression.ExclusiveOr(bExpresionBase, bExpresion),
_ => throw new ArgumentException("FilterLogic is not valid.", nameof(filterLogic)),
};

View File

@@ -179,4 +179,4 @@ public class SelectProviderInput
/// 指定存储桶名称
/// </summary>
public string? BucketName { get; set; }
}
}

View File

@@ -4,8 +4,6 @@
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using OnceMi.AspNetCore.OSS;
namespace Admin.NET.Core.Service;
/// <summary>
@@ -204,7 +202,7 @@ public class MultiOSSFileProvider : ICustomFileProvider, ITransient
"ALIYUN" => $"{protocol}://{bucketName}.{provider.Endpoint}/{filePath.TrimStart('/')}",
"QCLOUD" => $"{protocol}://{bucketName}-{provider.Endpoint}.cos.{provider.Region}.myqcloud.com/{filePath.TrimStart('/')}",
"MINIO" => $"{protocol}://{provider.Endpoint}/{bucketName}/{filePath.TrimStart('/')}",
_ => throw Oops.Oh($"不支持的OSS提供者: {provider.Provider}")
_ => throw Oops.Oh($"不支持的OSS提供者: {provider.Provider}")
};
}
@@ -254,4 +252,4 @@ public class MultiOSSFileProvider : ICustomFileProvider, ITransient
return Task.FromResult<SysFileProvider?>(null);
}
}
}
}

View File

@@ -1,7 +1,4 @@
using OnceMi.AspNetCore.OSS;
using System.Collections.Concurrent;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace Admin.NET.Core.Service;
@@ -211,4 +208,4 @@ public class OSSServiceManager : IOSSServiceManager, ITransient
_disposed = true;
}
}
}
}

View File

@@ -87,10 +87,6 @@ public class SysFileProviderController : IDynamicApiController, ITransient
await _fileProviderService.DeleteFileProvider(input);
}
/// <summary>
/// 根据存储桶名称获取存储提供者 🔖
/// </summary>
@@ -183,12 +179,8 @@ public class SysFileProviderController : IDynamicApiController, ITransient
{
return await _fileProviderService.GetBucketProviderMapping();
}
}
/// <summary>
/// 批量启用/禁用存储提供者输入参数
/// </summary>
@@ -204,4 +196,4 @@ public class BatchEnableProviderInput
/// 是否启用
/// </summary>
public bool IsEnable { get; set; }
}
}

View File

@@ -349,7 +349,6 @@ public class SysFileProviderService : IDynamicApiController, ITransient
await Task.CompletedTask;
}
/// <summary>
/// 获取所有可用的存储桶列表
/// </summary>
@@ -497,7 +496,7 @@ public class SysFileProviderService : IDynamicApiController, ITransient
{
// 确保只有一个默认提供者将其他提供者的默认标识设为false
await _sysFileProviderRep.AsUpdateable()
.SetColumns(p => p.IsDefault == false)
.SetColumns(p => p.IsDefault == false)
.Where(p => p.IsDefault == true && p.Id != provider.Id)
.ExecuteCommandAsync();
}
@@ -506,7 +505,6 @@ public class SysFileProviderService : IDynamicApiController, ITransient
{
provider.IsDefault ??= false;
}
// 检查是否还有其他默认提供者,如果没有且当前提供者启用,则设为默认
var hasDefaultProvider = await _sysFileProviderRep.AsQueryable()
@@ -519,4 +517,4 @@ public class SysFileProviderService : IDynamicApiController, ITransient
provider.IsDefault = true;
}
}
}
}

View File

@@ -7,7 +7,6 @@
using Aliyun.OSS.Util;
using Furion.AspNetCore;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Configuration;
namespace Admin.NET.Core.Service;

View File

@@ -153,13 +153,14 @@ public class SysRegionService : IDynamicApiController, ITransient
var syncLevel = await _sysConfigService.GetConfigValue<int>(ConfigConst.SysRegionSyncLevel);
if (syncLevel is < 1 or > 5) syncLevel = 3;//默认区县级
await _sysRegionRep.AsTenant().UseTranAsync(async () => {
await _sysRegionRep.AsTenant().UseTranAsync(async () =>
{
await _sysRegionRep.DeleteAsync(u => u.Id > 0);
await SyncByMap(syncLevel);
}, err => {
}, err =>
{
throw Oops.Oh(ErrorCodeEnum.R2005, err.Message);
});
// var context = BrowsingContext.New(AngleSharp.Configuration.Default.WithDefaultLoader());
// var dom = await context.OpenAsync(_url);
@@ -349,7 +350,7 @@ public class SysRegionService : IDynamicApiController, ITransient
list.Add(county);
}
}
// 按省份同步快速写入提升同步效率,全部一次性写入容易出现从统计局获取数据失败
// 仅当数据量大于1000或非Oracle数据库时采用大数据量写入方式SqlSugar官方已说明数据量小于1000时其性能不如普通插入, oracle此方法不支持事务
if (list.Count > 1000 && _sysRegionRep.Context.CurrentConnectionConfig.DbType != SqlSugar.DbType.Oracle)
@@ -359,7 +360,7 @@ public class SysRegionService : IDynamicApiController, ITransient
{
await _sysRegionRep.Context.Fastest<SysRegion>().BulkCopyAsync(list);
}
catch(SqlSugarException)
catch (SqlSugarException)
{
// 若写入失败则尝试普通插入方式
await _sysRegionRep.InsertRangeAsync(list);

View File

@@ -19,6 +19,7 @@ public class SysRoleService : IDynamicApiController, ITransient
private readonly SysRoleOrgService _sysRoleOrgService;
private readonly SysMenuService _sysMenuService;
private readonly SysOrgService _sysOrgService;
private readonly SysCacheService _sysCacheService;
public SysRoleService(UserManager userManager,
SysOrgService sysOrgService,
@@ -26,7 +27,8 @@ public class SysRoleService : IDynamicApiController, ITransient
SysRoleOrgService sysRoleOrgService,
SqlSugarRepository<SysRole> sysRoleRep,
SysRoleMenuService sysRoleMenuService,
SysUserRoleService sysUserRoleService)
SysUserRoleService sysUserRoleService,
SysCacheService sysCacheService)
{
_userManager = userManager;
_sysRoleRep = sysRoleRep;
@@ -35,6 +37,7 @@ public class SysRoleService : IDynamicApiController, ITransient
_sysRoleOrgService = sysRoleOrgService;
_sysRoleMenuService = sysRoleMenuService;
_sysUserRoleService = sysUserRoleService;
_sysCacheService = sysCacheService;
}
/// <summary>
@@ -164,6 +167,10 @@ public class SysRoleService : IDynamicApiController, ITransient
[DisplayName("授权角色菜单")]
public async Task GrantMenu(RoleMenuInput input)
{
if (input.MenuIdList == null || input.MenuIdList.Count < 1) return;
await ClearUserApiCache(input.Id);
await _sysRoleMenuService.GrantRoleMenu(input);
}
@@ -251,4 +258,19 @@ public class SysRoleService : IDynamicApiController, ITransient
.Where(u => u.Id == input.Id)
.ExecuteCommandAsync();
}
/// <summary>
/// 删除与该角色相关的用户接口缓存
/// </summary>
/// <param name="roleId"></param>
/// <returns></returns>
[NonAction]
public async Task ClearUserApiCache(long roleId)
{
var userIdList = await _sysUserRoleService.GetUserIdList(roleId);
foreach (var userId in userIdList)
{
_sysCacheService.Remove($"{CacheConst.KeyUserButton}{userId}");
}
}
}

View File

@@ -4,8 +4,6 @@
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using NewLife.Reflection;
namespace Admin.NET.Core;
/// <summary>
@@ -39,7 +37,7 @@ public class SqlSugarRepository<T> : SimpleClient<T>, ISqlSugarRepository<T> whe
return;
// 看请求头有没有租户id
var tenantId = App.HttpContext?.Request.Headers.GetValue(ClaimConst.TenantId, false)?.ToString();
var tenantId = App.HttpContext?.Request.Headers[ClaimConst.TenantId].FirstOrDefault();
if (tenantId == SqlSugarConst.MainConfigId) return;
else if (string.IsNullOrWhiteSpace(tenantId))
{

View File

@@ -417,7 +417,7 @@ public static class SqlSugarSetup
if (config.DbType != DbType.Oracle) dbProvider.DbMaintenance.CreateDatabase();
}
// 等待数据库连接就绪
// 等待数据库连接就绪
WaitForDatabaseReady(dbProvider);
// 初始化表结构

View File

@@ -25,6 +25,4 @@ public class TenantHeaderOperationFilter : IOperationFilter
Description = "租户ID留空表示默认租户"
});
}
}
}

View File

@@ -12,7 +12,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Furion.Xunit" Version="4.9.7.208" />
<PackageReference Include="Furion.Xunit" Version="4.9.7.211" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="Selenium.Support" Version="4.38.0" />
<PackageReference Include="Selenium.WebDriver" Version="4.38.0" />

View File

@@ -379,14 +379,15 @@ public class Startup : AppStartup
{
groupInfo.Description += "<br/><u><b><font color='FF0000'> 👮不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!</font></b></u>";
}
options.ConfigureSwagger(m => {
options.ConfigureSwagger(m =>
{
m.OpenApiVersion = Microsoft.OpenApi.OpenApiSpecVersion.OpenApi3_0;
});
});
#if NET10_0_OR_GREATER
app.UseAutoVersionUpdate();
#endif
#endif
app.UseEndpoints(endpoints =>
{

View File

@@ -10,7 +10,7 @@ namespace Admin.NET.Plugin.DingTalk;
/// 钉钉角色信息
/// </summary>
[SugarTable(null, "钉钉角色表")]
public class DingTalkRoleUser : EntityBase
public class DingTalkRoleUser : EntityBaseDel
{
/// <summary>
/// 钉钉用户id

View File

@@ -25,7 +25,7 @@
<ItemGroup>
<PackageReference Include="ClosedXML" Version="0.105.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="4.14.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="5.0.0" />
<PackageReference Include="Rezero.Api" Version="1.8.30" />
</ItemGroup>

View File

@@ -2,7 +2,7 @@
"name": "admin.net",
"type": "module",
"version": "2.4.33",
"lastBuildTime": "2025.11.16",
"lastBuildTime": "2025.11.23",
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
"author": "zuohuaijun",
"license": "MIT",
@@ -44,15 +44,15 @@
"echarts-gl": "^2.0.9",
"echarts-wordcloud": "^2.1.0",
"element-plus": "^2.11.8",
"ezuikit-js": "^8.1.16",
"ezuikit-js": "^8.1.17",
"js-cookie": "^3.0.5",
"js-table2excel": "^1.1.2",
"json-editor-vue": "^0.18.1",
"jsplumb": "^2.15.6",
"lodash-es": "^4.17.21",
"md-editor-v3": "^6.0.1",
"md-editor-v3": "^6.2.0",
"mitt": "^3.0.1",
"monaco-editor": "^0.54.0",
"monaco-editor": "^0.55.1",
"mqtt": "^5.14.1",
"nprogress": "^0.2.0",
"pinia": "^3.0.4",
@@ -72,7 +72,7 @@
"vue-demi": "^0.14.10",
"vue-draggable-plus": "^0.6.0",
"vue-grid-layout": "3.0.0-beta1",
"vue-i18n": "^11.1.12",
"vue-i18n": "^11.2.1",
"vue-json-pretty": "^2.6.0",
"vue-plugin-hiprint": "^0.0.60",
"vue-router": "^4.6.3",
@@ -89,25 +89,25 @@
"@types/node": "^22.19.1",
"@types/nprogress": "^0.2.3",
"@types/sortablejs": "^1.15.9",
"@typescript-eslint/eslint-plugin": "^8.46.4",
"@typescript-eslint/parser": "^8.46.4",
"@vitejs/plugin-vue": "^6.0.1",
"@vitejs/plugin-vue-jsx": "^5.1.1",
"@typescript-eslint/eslint-plugin": "^8.47.0",
"@typescript-eslint/parser": "^8.47.0",
"@vitejs/plugin-vue": "^6.0.2",
"@vitejs/plugin-vue-jsx": "^5.1.2",
"@vue/compiler-sfc": "^3.5.24",
"cli-progress": "^3.12.0",
"code-inspector-plugin": "^1.2.10",
"code-inspector-plugin": "^1.3.0",
"colors": "^1.4.0",
"dotenv": "^17.2.3",
"eslint": "^9.39.1",
"eslint-plugin-vue": "^10.5.1",
"eslint-plugin-vue": "^10.6.0",
"globals": "^16.5.0",
"less": "^4.4.2",
"prettier": "^3.6.2",
"rollup-plugin-visualizer": "^6.0.5",
"sass": "^1.94.0",
"sass": "^1.94.2",
"terser": "^5.44.1",
"typescript": "^5.9.3",
"vite": "^7.2.2",
"vite": "^7.2.4",
"vite-auto-i18n-plugin": "^1.1.13",
"vite-plugin-cdn-import": "^1.0.1",
"vite-plugin-compression2": "^2.3.1",