Przeglądaj źródła

perf: 😀性能优化

喵你个旺呀 1 rok temu
rodzic
commit
1bffd19bb6

+ 7 - 2
Admin.NET/Admin.NET.Core/Attribute/DictAttribute.cs

@@ -28,6 +28,11 @@ public class DictAttribute : ValidationAttribute, ITransient
     /// </summary>
     public bool AllowNullValue { get; set; } = false;
 
+    /// <summary>
+    /// 字典值服务
+    /// </summary>
+    private readonly SysDictDataService _sysDictDataService = App.GetRequiredService<SysDictDataService>();
+
     /// <summary>
     /// 字典值合规性校验特性
     /// </summary>
@@ -55,8 +60,8 @@ public class DictAttribute : ValidationAttribute, ITransient
         // 是否忽略空字符串
         if (AllowEmptyStrings && string.IsNullOrEmpty(valueAsString)) return ValidationResult.Success;
 
-        var sysDictDataServiceProvider = App.GetRequiredService<SysDictDataService>();
-        var dictDataList = sysDictDataServiceProvider.GetDataList(DictTypeCode).Result;
+        // 获取字典值列表
+        var dictDataList = _sysDictDataService.GetDataList(DictTypeCode).Result;
 
         // 获取枚举类型,可能存在Nullable类型,所以需要尝试获取最终类型
         var type = value?.GetType();

+ 9 - 5
Admin.NET/Admin.NET.Core/Attribute/IdempotentAttribute.cs

@@ -35,6 +35,11 @@ public class IdempotentAttribute : Attribute, IAsyncActionFilter
     /// </summary>
     public bool ThrowBah { get; set; }
 
+    /// <summary>
+    /// 缓存服务
+    /// </summary>
+    private readonly SysCacheService _sysCacheService = App.GetRequiredService<SysCacheService>();
+
     public IdempotentAttribute()
     {
     }
@@ -54,14 +59,13 @@ public class IdempotentAttribute : Attribute, IAsyncActionFilter
         }
 
         var cacheKey = MD5Encryption.Encrypt($"{CacheKey}{path}{userId}{parameters}");
-        var sysCacheService = App.GetRequiredService<SysCacheService>();
-        if (sysCacheService.ExistKey(cacheKey))
+        if (_sysCacheService.ExistKey(cacheKey))
         {
             if (ThrowBah) throw Oops.Oh(Message);
 
             try
             {
-                var cachedResult = sysCacheService.Get<ResponseData>(cacheKey);
+                var cachedResult = _sysCacheService.Get<ResponseData>(cacheKey);
                 context.Result = new ObjectResult(cachedResult.Value);
             }
             catch (Exception ex)
@@ -72,7 +76,7 @@ public class IdempotentAttribute : Attribute, IAsyncActionFilter
         else
         {
             // 先加入一个空缓存,防止第一次请求结果没回来导致连续请求
-            sysCacheService.Set(cacheKey, "", cacheExpireTime);
+            _sysCacheService.Set(cacheKey, "", cacheExpireTime);
             var resultContext = await next();
             if (resultContext.Result is ObjectResult objectResult)
             {
@@ -82,7 +86,7 @@ public class IdempotentAttribute : Attribute, IAsyncActionFilter
                     Type = valueType.Name,
                     Value = objectResult.Value
                 };
-                sysCacheService.Set(cacheKey, responseData, cacheExpireTime);
+                _sysCacheService.Set(cacheKey, responseData, cacheExpireTime);
             }
         }
     }

+ 7 - 2
Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs

@@ -23,6 +23,8 @@ public class SysAuthService : IDynamicApiController, ITransient
     private readonly SysOnlineUserService _sysOnlineUserService;
     private readonly SysConfigService _sysConfigService;
     private readonly SysUserService _sysUserService;
+    private readonly SysSmsService _sysSmsService;
+    private readonly SysLdapService _sysLdapService;
     private readonly ICaptcha _captcha;
     private readonly SysCacheService _sysCacheService;
 
@@ -31,6 +33,8 @@ public class SysAuthService : IDynamicApiController, ITransient
         IHttpContextAccessor httpContextAccessor,
         SysOnlineUserService sysOnlineUserService,
         SysConfigService sysConfigService,
+        SysLdapService sysLdapService,
+        SysSmsService sysSmsService,
         SysCacheService sysCacheService,
         SysMenuService sysMenuService,
         SysUserService sysUserService,
@@ -40,6 +44,7 @@ public class SysAuthService : IDynamicApiController, ITransient
         _captcha = captcha;
         _sysUserRep = sysUserRep;
         _userManager = userManager;
+        _sysSmsService = sysSmsService;
         _sysUserService = sysUserService;
         _sysMenuService = sysMenuService;
         _sysCacheService = sysCacheService;
@@ -183,7 +188,7 @@ public class SysAuthService : IDynamicApiController, ITransient
             {
                 VerifyPassword(password, keyPasswordErrorTimes, passwordErrorTimes, user);
             }
-            else if (!await App.GetRequiredService<SysLdapService>().AuthAccount(user.TenantId.Value, userLdap.Account, CryptogramUtil.Decrypt(password)))
+            else if (!await _sysLdapService.AuthAccount(user.TenantId!.Value, userLdap.Account, CryptogramUtil.Decrypt(password)))
             {
                 _sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
                 throw Oops.Oh(ErrorCodeEnum.D1000);
@@ -205,7 +210,7 @@ public class SysAuthService : IDynamicApiController, ITransient
     public virtual async Task<LoginOutput> LoginPhone([Required] LoginPhoneInput input)
     {
         // 校验短信验证码
-        App.GetRequiredService<SysSmsService>().VerifyCode(new SmsVerifyCodeInput { Phone = input.Phone, Code = input.Code });
+        _sysSmsService.VerifyCode(new SmsVerifyCodeInput { Phone = input.Phone, Code = input.Code });
 
         // 获取登录租户和用户
         var (_, user) = await GetLoginUserAndTenant(input.TenantId, phone: input.Phone);

+ 11 - 3
Admin.NET/Admin.NET.Core/Service/Auth/SysLdapService.cs

@@ -15,12 +15,20 @@ namespace Admin.NET.Core;
 public class SysLdapService : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<SysLdap> _sysLdapRep;
+    private readonly SysUserLdapService _sysUserLdapService;
+    private readonly SysOrgService _sysOrgService;
     private readonly UserManager _userManager;
 
-    public SysLdapService(SqlSugarRepository<SysLdap> sysLdapRep, UserManager userManager)
+    public SysLdapService(
+        SqlSugarRepository<SysLdap> sysLdapRep,
+        SysUserLdapService sysUserLdapService,
+        SysOrgService sysOrgService,
+        UserManager userManager)
     {
         _sysLdapRep = sysLdapRep;
         _userManager = userManager;
+        _sysOrgService = sysOrgService;
+        _sysUserLdapService = sysUserLdapService;
     }
 
     /// <summary>
@@ -227,7 +235,7 @@ public class SysLdapService : IDynamicApiController, ITransient
 
             if (userLdapList.Count == 0) return null;
 
-            await App.GetRequiredService<SysUserLdapService>().InsertUserLdapList(sysLdap.TenantId!.Value, userLdapList);
+            await _sysUserLdapService.InsertUserLdapList(sysLdap.TenantId!.Value, userLdapList);
             return userLdapList;
         }
         catch (LdapException e)
@@ -367,7 +375,7 @@ public class SysLdapService : IDynamicApiController, ITransient
             if (orgList.Count == 0)
                 return;
 
-            await App.GetRequiredService<SysOrgService>().BatchAddOrgs(orgList);
+            await _sysOrgService.BatchAddOrgs(orgList);
         }
         catch (LdapException e)
         {

+ 4 - 4
Admin.NET/Admin.NET.Core/SignatureAuth/SignatureAuthenticationHandler.cs

@@ -35,6 +35,8 @@ public sealed class SignatureAuthenticationHandler : AuthenticationHandler<Signa
     }
 #endif
 
+    private readonly SysCacheService _sysCacheService = App.GetRequiredService<SysCacheService>();
+
     private new SignatureAuthenticationEvent Events
     {
         get => (SignatureAuthenticationEvent)base.Events;
@@ -91,11 +93,9 @@ public sealed class SignatureAuthenticationHandler : AuthenticationHandler<Signa
             return await AuthenticateResultFailAsync("sign 无效的签名");
 
         // 重放检测
-        var cache = App.GetRequiredService<SysCacheService>();
         var cacheKey = $"{CacheConst.KeyOpenAccessNonce}{accessKey}|{nonce}";
-        if (cache.ExistKey(cacheKey))
-            return await AuthenticateResultFailAsync("重复的请求");
-        cache.Set(cacheKey, null, Options.AllowedDateDrift * 2); // 缓存过期时间为偏差范围时间的2倍
+        if (_sysCacheService.ExistKey(cacheKey)) return await AuthenticateResultFailAsync("重复的请求");
+        _sysCacheService.Set(cacheKey, null, Options.AllowedDateDrift * 2); // 缓存过期时间为偏差范围时间的2倍
 
         // 已验证成功
         var signatureValidatedContext = new SignatureValidatedContext(Context, Scheme, Options)

+ 7 - 8
Admin.NET/Admin.NET.Core/SqlSugar/SqlSugarFilter.cs

@@ -12,6 +12,8 @@ public static class SqlSugarFilter
     /// 缓存全局查询过滤器(内存缓存)
     /// </summary>
     private static readonly ICache Cache = NewLife.Caching.Cache.Default;
+    private static readonly SysOrgService SysOrgService = App.GetRequiredService<SysOrgService>();
+    private static readonly SysCacheService SysCacheService = App.GetRequiredService<SysCacheService>();
 
     /// <summary>
     /// 删除用户机构缓存
@@ -20,14 +22,12 @@ public static class SqlSugarFilter
     /// <param name="dbConfigId"></param>
     public static void DeleteUserOrgCache(long userId, string dbConfigId)
     {
-        var sysCacheService = App.GetRequiredService<SysCacheService>();
-
         // 删除用户机构集合缓存
-        sysCacheService.Remove($"{CacheConst.KeyUserOrg}{userId}");
+        SysCacheService.Remove($"{CacheConst.KeyUserOrg}{userId}");
         // 删除最大数据权限缓存
-        sysCacheService.Remove($"{CacheConst.KeyRoleMaxDataScope}{userId}");
+        SysCacheService.Remove($"{CacheConst.KeyRoleMaxDataScope}{userId}");
         // 用户权限缓存(按钮集合)
-        sysCacheService.Remove($"{CacheConst.KeyUserButton}{userId}");
+        SysCacheService.Remove($"{CacheConst.KeyUserButton}{userId}");
         // 删除用户机构(数据范围)缓存——过滤器
         Cache.Remove($"db:{dbConfigId}:orgList:{userId}");
     }
@@ -119,9 +119,8 @@ public static class SqlSugarFilter
             // 获取用户所属机构,保证同一作用域
             Scoped.Create((factory, scope) =>
             {
-                var services = scope.ServiceProvider;
-                services.GetRequiredService<SysOrgService>().GetUserOrgIdList().GetAwaiter().GetResult();
-                maxDataScope = services.GetRequiredService<SysCacheService>().Get<int>(CacheConst.KeyRoleMaxDataScope + userId);
+                SysOrgService.GetUserOrgIdList().GetAwaiter().GetResult();
+                maxDataScope = SysCacheService.Get<int>(CacheConst.KeyRoleMaxDataScope + userId);
             });
         }
         if (maxDataScope != (int)DataScopeEnum.Self) return maxDataScope;

+ 10 - 9
Admin.NET/Admin.NET.Core/Utils/CommonUtil.cs

@@ -17,6 +17,10 @@ namespace Admin.NET.Core;
 /// </summary>
 public static class CommonUtil
 {
+    private static readonly SysCacheService SysCacheService = App.GetRequiredService<SysCacheService>();
+    private static readonly SysFileService SysFileService = App.GetRequiredService<SysFileService>();
+    private static readonly SqlSugarRepository<SysDictData> SysDictDataRep = App.GetRequiredService<SqlSugarRepository<SysDictData>>();
+
     /// <summary>
     /// 根据字符串获取固定整型哈希值
     /// </summary>
@@ -245,8 +249,8 @@ public static class CommonUtil
         resultStream.Seek(0, SeekOrigin.Begin);
         var userId = App.User?.FindFirst(ClaimConst.UserId)?.Value;
 
-        App.GetRequiredService<SysCacheService>().Remove(CacheConst.KeyExcelTemp + userId);
-        App.GetRequiredService<SysCacheService>().Set(CacheConst.KeyExcelTemp + userId, resultStream, TimeSpan.FromMinutes(5));
+        SysCacheService.Remove(CacheConst.KeyExcelTemp + userId);
+        SysCacheService.Set(CacheConst.KeyExcelTemp + userId, resultStream, TimeSpan.FromMinutes(5));
 
         var message = string.Empty;
         if (!res.HasError) return res.Data;
@@ -273,15 +277,14 @@ public static class CommonUtil
     /// <returns></returns>
     public static async Task<List<T>> ImportExcelDataAsync<T>([Required] IFormFile file) where T : class, new()
     {
-        var sysFileService = App.GetRequiredService<SysFileService>();
-        var newFile = await sysFileService.UploadFile(new UploadFileInput { File = file });
+        var newFile = await SysFileService.UploadFile(new UploadFileInput { File = file });
         var filePath = Path.Combine(App.WebHostEnvironment.WebRootPath, newFile.FilePath!, newFile.Id + newFile.Suffix);
 
         IImporter importer = new ExcelImporter();
         var res = await importer.Import<T>(filePath);
 
         // 删除文件
-        _ = sysFileService.DeleteFile(new DeleteFileInput { Id = newFile.Id });
+        _ = SysFileService.DeleteFile(new DeleteFileInput { Id = newFile.Id });
 
         if (res == null)
             throw Oops.Oh("导入数据为空");
@@ -402,7 +405,6 @@ public static class CommonUtil
         // 整理导入对象的属性名称,<字典数据,原属性信息,目标属性信息>
         var propMappings = new Dictionary<string, Tuple<Dictionary<object, string>, PropertyInfo, PropertyInfo>>();
 
-        var dictService = App.GetRequiredService<SqlSugarRepository<SysDictData>>();
         var targetProps = typeof(TTarget).GetProperties().ToList();
         var sourceProps = typeof(TSource).GetProperties().ToDictionary(u => u.Name);
         foreach (var propertyInfo in targetProps)
@@ -411,14 +413,13 @@ public static class CommonUtil
             if (attrs != null && !string.IsNullOrWhiteSpace(attrs.TypeCode))
             {
                 var targetProp = sourceProps[attrs.TargetPropName];
-                var mappingValues = dictService.Context.Queryable<SysDictType, SysDictData>((u, a) =>
+                var mappingValues = SysDictDataRep.Context.Queryable<SysDictType, SysDictData>((u, a) =>
                     new JoinQueryInfos(JoinType.Inner, u.Id == a.DictTypeId))
                     .Where(u => u.Code == attrs.TypeCode)
                     .Where((u, a) => u.Status == StatusEnum.Enable && a.Status == StatusEnum.Enable)
                     .Select((u, a) => new
                     {
-                        Label = a.Label,
-                        Value = a.Value
+                        a.Label, a.Value
                     }).ToList()
                     .ToDictionary(u => u.Value.ParseTo(targetProp.PropertyType), u => u.Label);
                 propMappings.Add(propertyInfo.Name, new Tuple<Dictionary<object, string>, PropertyInfo, PropertyInfo>(mappingValues, targetProp, propertyInfo));

+ 61 - 75
Admin.NET/Admin.NET.Web.Core/Handlers/JwtHandler.cs

@@ -11,98 +11,84 @@ using Furion.Authorization;
 using Furion.DataEncryption;
 using Microsoft.AspNetCore.Authorization;
 using Microsoft.AspNetCore.Http;
-using Microsoft.Extensions.DependencyInjection;
 using System;
 using System.Threading.Tasks;
 
-namespace Admin.NET.Web.Core
+namespace Admin.NET.Web.Core;
+
+public class JwtHandler : AppAuthorizeHandler
 {
-    public class JwtHandler : AppAuthorizeHandler
-    {
-        private readonly IServiceProvider _serviceProvider;
+    private readonly SysCacheService _sysCacheService = App.GetRequiredService<SysCacheService>();
+    private readonly SysConfigService _sysConfigService = App.GetRequiredService<SysConfigService>();
+    private static readonly SysMenuService SysMenuService = App.GetRequiredService<SysMenuService>();
 
-        public JwtHandler(IServiceProvider serviceProvider)
+    /// <summary>
+    /// 自动刷新Token
+    /// </summary>
+    /// <param name="context"></param>
+    /// <param name="httpContext"></param>
+    /// <returns></returns>
+    public override async Task HandleAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
+    {
+        // 若当前账号存在黑名单中则授权失败
+        if (_sysCacheService.ExistKey($"{CacheConst.KeyBlacklist}{context.User.FindFirst(ClaimConst.UserId)?.Value}"))
         {
-            _serviceProvider = serviceProvider;
+            context.Fail();
+            context.GetCurrentHttpContext().SignoutToSwagger();
+            return;
         }
 
-        /// <summary>
-        /// 自动刷新Token
-        /// </summary>
-        /// <param name="context"></param>
-        /// <param name="httpContext"></param>
-        /// <returns></returns>
-        public override async Task HandleAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
+        var tokenExpire = await _sysConfigService.GetTokenExpire();
+        var refreshTokenExpire = await _sysConfigService.GetRefreshTokenExpire();
+        if (JWTEncryption.AutoRefreshToken(context, context.GetCurrentHttpContext(), tokenExpire, refreshTokenExpire))
         {
-            // var serviceProvider = context.GetCurrentHttpContext().RequestServices;
-            using var serviceScope = _serviceProvider.CreateScope();
-
-            // 若当前账号存在黑名单中则授权失败
-            var sysCacheService = serviceScope.ServiceProvider.GetRequiredService<SysCacheService>();
-            if (sysCacheService.ExistKey($"{CacheConst.KeyBlacklist}{context.User.FindFirst(ClaimConst.UserId)?.Value}"))
-            {
-                context.Fail();
-                context.GetCurrentHttpContext().SignoutToSwagger();
-                return;
-            }
-
-            var sysConfigService = serviceScope.ServiceProvider.GetRequiredService<SysConfigService>();
-            var tokenExpire = await sysConfigService.GetTokenExpire();
-            var refreshTokenExpire = await sysConfigService.GetRefreshTokenExpire();
-            if (JWTEncryption.AutoRefreshToken(context, context.GetCurrentHttpContext(), tokenExpire, refreshTokenExpire))
-            {
-                await AuthorizeHandleAsync(context);
-            }
-            else
-            {
-                context.Fail(); // 授权失败
-                var currentHttpContext = context.GetCurrentHttpContext();
-                if (currentHttpContext == null)
-                    return;
-                // 跳过由于 SignatureAuthentication 引发的失败
-                if (currentHttpContext.Items.ContainsKey(SignatureAuthenticationDefaults.AuthenticateFailMsgKey))
-                    return;
-                currentHttpContext.SignoutToSwagger();
-            }
+            await AuthorizeHandleAsync(context);
         }
-
-        public override async Task<bool> PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
+        else
         {
-            // 已自动验证 Jwt Token 有效性
-            return await CheckAuthorizeAsync(httpContext);
+            context.Fail(); // 授权失败
+            var currentHttpContext = context.GetCurrentHttpContext();
+            if (currentHttpContext == null) return;
+
+            // 跳过由于 SignatureAuthentication 引发的失败
+            if (currentHttpContext.Items.ContainsKey(SignatureAuthenticationDefaults.AuthenticateFailMsgKey)) return;
+            currentHttpContext.SignoutToSwagger();
         }
+    }
 
-        /// <summary>
-        /// 权限校验核心逻辑
-        /// </summary>
-        /// <param name="httpContext"></param>
-        /// <returns></returns>
-        private static async Task<bool> CheckAuthorizeAsync(DefaultHttpContext httpContext)
-        {
-            // 登录模式判断PC、APP
-            if (App.User.FindFirst(ClaimConst.LoginMode)?.Value == ((int)LoginModeEnum.APP).ToString())
-                return true;
+    public override async Task<bool> PipelineAsync(AuthorizationHandlerContext context, DefaultHttpContext httpContext)
+    {
+        // 已自动验证 Jwt Token 有效性
+        return await CheckAuthorizeAsync(httpContext);
+    }
 
-            // 排除超管
-            if (App.User.FindFirst(ClaimConst.AccountType)?.Value == ((int)AccountTypeEnum.SuperAdmin).ToString())
-                return true;
+    /// <summary>
+    /// 权限校验核心逻辑
+    /// </summary>
+    /// <param name="httpContext"></param>
+    /// <returns></returns>
+    private static async Task<bool> CheckAuthorizeAsync(DefaultHttpContext httpContext)
+    {
+        // 登录模式判断PC、APP
+        if (App.User.FindFirst(ClaimConst.LoginMode)?.Value == ((int)LoginModeEnum.APP).ToString())
+            return true;
 
-            // 路由名称
-            var routeName = httpContext.Request.Path.StartsWithSegments("/api")
-                ? httpContext.Request.Path.Value[5..].Replace("/", ":")
-                : httpContext.Request.Path.Value[1..].Replace("/", ":");
+        // 排除超管
+        if (App.User.FindFirst(ClaimConst.AccountType)?.Value == ((int)AccountTypeEnum.SuperAdmin).ToString())
+            return true;
 
-            var serviceScope = httpContext.RequestServices.CreateScope();
-            var sysMenuService = serviceScope.ServiceProvider.GetRequiredService<SysMenuService>();
+        // 路由名称
+        var routeName = httpContext.Request.Path.StartsWithSegments("/api")
+            ? httpContext.Request.Path.Value![5..].Replace("/", ":")
+            : httpContext.Request.Path.Value![1..].Replace("/", ":");
 
-            // 获取用户拥有按钮权限集合
-            var ownBtnPermList = await sysMenuService.GetOwnBtnPermList();
-            if (ownBtnPermList.Exists(u => routeName.Equals(u, StringComparison.CurrentCultureIgnoreCase)))
-                return true;
+        // 获取用户拥有按钮权限集合
+        var ownBtnPermList = await SysMenuService.GetOwnBtnPermList();
+        if (ownBtnPermList.Exists(u => routeName.Equals(u, StringComparison.CurrentCultureIgnoreCase)))
+            return true;
 
-            // 获取系统所有按钮权限集合
-            var allBtnPermList = await sysMenuService.GetAllBtnPermList();
-            return allBtnPermList.TrueForAll(u => !routeName.Equals(u, StringComparison.CurrentCultureIgnoreCase));
-        }
+        // 获取系统所有按钮权限集合
+        var allBtnPermList = await SysMenuService.GetAllBtnPermList();
+        return allBtnPermList.TrueForAll(u => !routeName.Equals(u, StringComparison.CurrentCultureIgnoreCase));
     }
 }