1
0
Эх сурвалжийг харах

实现数据权限过滤器功能

zhontai 2 жил өмнө
parent
commit
90cc1f9edf

+ 3 - 4
src/platform/ZhonTai.Admin/Core/Auth/IUser.cs

@@ -1,5 +1,4 @@
-using ZhonTai.Admin.Domain.Role;
-using ZhonTai.Admin.Domain.Tenant;
+using ZhonTai.Admin.Domain.Tenant;
 using ZhonTai.Admin.Domain.User;
 using ZhonTai.Admin.Domain.User.Dto;
 
@@ -61,7 +60,7 @@ public interface IUser
     string DbKey { get; }
 
     /// <summary>
-    /// 当前用户
+    /// 数据权限
     /// </summary>
-    CurrentUserDto CurrentUser { get; }
+    DataPermissionDto DataPermission { get; }
 }

+ 15 - 19
src/platform/ZhonTai.Admin/Core/Auth/User.cs

@@ -174,28 +174,24 @@ public class User : IUser
     }
 
     /// <summary>
-    /// 当前用户
+    /// 获得数据权限
     /// </summary>
-    public virtual CurrentUserDto CurrentUser
+    /// <returns></returns>
+    DataPermissionDto GetDataPermission()
     {
-        get
+        var cache = _accessor?.HttpContext?.RequestServices.GetRequiredService<ICacheTool>();
+        if (cache == null)
         {
-            var userRepository = _accessor?.HttpContext?.RequestServices.GetRequiredService<IUserRepository>();
-            if(userRepository == null)
-            {
-                return null;
-            }
-            else
-            {
-                return userRepository.GetCurrentUserAsync().Result;
-            }
-            
-            //var cache = _accessor?.HttpContext?.RequestServices.GetRequiredService<ICacheTool>();
-            //var key = CacheKeys.UserInfo + Id;
-            //return cache.GetOrSetAsync(key, async () =>
-            //{
-            //    return await userRepsitory.GetCurrentUserAsync();
-            //}).Result;
+            return null;
+        }
+        else
+        {
+            return cache.Get<DataPermissionDto>(CacheKeys.DataPermission + Id);
         }
     }
+
+    /// <summary>
+    /// 数据权限
+    /// </summary>
+    public virtual DataPermissionDto DataPermission => GetDataPermission();
 }

+ 6 - 6
src/platform/ZhonTai.Admin/Core/Consts/CacheKeys.cs

@@ -13,23 +13,23 @@ public static partial class CacheKeys
     /// 验证码 admin:captcha:guid
     /// </summary>
     [Description("验证码")]
-    public const string Captcha = "admin:captcha";
+    public const string Captcha = "admin:captcha:";
 
     /// <summary>
     /// 密码加密 admin:password:encrypt:guid
     /// </summary>
     [Description("密码加密")]
-    public const string PassWordEncrypt = "admin:password:encrypt";
+    public const string PassWordEncrypt = "admin:password:encrypt:";
 
     /// <summary>
     /// 用户权限 admin:user:permissions:用户主键
     /// </summary>
     [Description("用户权限")]
-    public const string UserPermissions = "admin:user:permissions";
+    public const string UserPermissions = "admin:user:permissions:";
 
     /// <summary>
-    /// 用户信息 admin:user:info:用户主键
+    /// 数据权限 admin:user:data:permission:用户主键
     /// </summary>
-    [Description("用户信息")]
-    public const string UserInfo = "admin:user:info";
+    [Description("数据权限")]
+    public const string DataPermission = "admin:user:data:permission:";
 }

+ 6 - 0
src/platform/ZhonTai.Admin/Core/Consts/FilterNames.cs

@@ -19,6 +19,12 @@ public static partial class FilterNames
     [Description("租户")]
     public const string Tenant = "Tenant";
 
+    /// <summary>
+    /// 本人权限
+    /// </summary>
+    [Description("本人权限")]
+    public const string Self = "Selft";
+
     /// <summary>
     /// 数据权限
     /// </summary>

+ 26 - 5
src/platform/ZhonTai.Admin/Core/Db/DBServiceCollectionExtensions.cs

@@ -27,7 +27,7 @@ public static class DBServiceCollectionExtensions
     /// <param name="env"></param>
     /// <param name="hostAppOptions"></param>
     /// <returns></returns>
-    public static void AddAdminDb(this IServiceCollection services, FreeSqlCloud freeSqlCloud, IHostEnvironment env, HostAppOptions hostAppOptions)
+    public static void AddMasterDb(this IServiceCollection services, FreeSqlCloud freeSqlCloud, IHostEnvironment env, HostAppOptions hostAppOptions)
     {
         var dbConfig = ConfigHelper.Get<DbConfig>("dbconfig", env.EnvironmentName);
         var appConfig = ConfigHelper.Get<AppConfig>("appconfig", env.EnvironmentName);
@@ -82,10 +82,31 @@ public static class DBServiceCollectionExtensions
                 fsql.GlobalFilter.ApplyOnlyIf<ITenant>(FilterNames.Tenant, () => user?.Id > 0, a => a.TenantId == user.TenantId);
             }
 
-            //数据权限过滤器,CurrentUser动态查询无法禁用过滤器
-            //fsql.GlobalFilter.ApplyOnlyIf<IData>(FilterNames.Data,
-            //    () => user?.Id > 0 && user.Type == UserType.DefaultUser && user.CurrentUser?.DataScope != DataScope.All,
-            //    a => a.OwnerId == user.Id || user.CurrentUser.OrgIds.Contains(a.CreatedOrgId.Value));
+            //数据权限过滤器
+            fsql.GlobalFilter.ApplyOnlyIf<IData>(FilterNames.Self,
+                () =>
+                {
+                    if (!(user?.Id > 0))
+                        return false;
+                    var dataPermission = user.DataPermission;
+                    if (user.Type == UserType.DefaultUser && dataPermission != null)
+                        return dataPermission.DataScope != DataScope.All && dataPermission.OrgIds.Count == 0;
+                    return false;
+                },
+                a => a.OwnerId == user.Id
+            );
+            fsql.GlobalFilter.ApplyOnlyIf<IData>(FilterNames.Data,
+                () =>
+                {
+                    if (!(user?.Id > 0))
+                        return false;
+                    var dataPermission = user.DataPermission;
+                    if (user.Type == UserType.DefaultUser && dataPermission != null)
+                        return dataPermission.DataScope != DataScope.All && dataPermission.OrgIds.Count > 0;
+                    return false;
+                },
+                a => a.OwnerId == user.Id || user.DataPermission.OrgIds.Contains(a.OwnerOrgId.Value)
+            );
 
             //配置实体
             DbHelper.ConfigEntity(fsql, appConfig);

+ 2 - 2
src/platform/ZhonTai.Admin/Core/Db/DbHelper.cs

@@ -168,10 +168,10 @@ public class DbHelper
                         e.Value = user.UserName;
                     }
                     break;
-                case "CreatedOrgId":
+                case "OwnerOrgId":
                     if (e.Value == null || (long)e.Value == default || (long?)e.Value == default)
                     {
-                        e.Value = user.CurrentUser?.OrgId;
+                        e.Value = user.DataPermission?.OrgId;
                     }
                     break;
                 case "TenantId":

+ 2 - 2
src/platform/ZhonTai.Admin/Core/Entities/IData.cs

@@ -11,7 +11,7 @@ public interface IData
     long? OwnerId { get; set; }
 
     /// <summary>
-    /// 创建者部门Id
+    /// 拥有者部门Id
     /// </summary>
-    long? CreatedOrgId { get; set; }
+    long? OwnerOrgId { get; set; }
 }

+ 18 - 5
src/platform/ZhonTai.Admin/Core/HostApp.cs

@@ -48,6 +48,7 @@ using ZhonTai.Admin.Core.Startup;
 using ZhonTai.Admin.Core.Conventions;
 using FreeSql;
 using ZhonTai.Admin.Core.Db.Transaction;
+using ZhonTai.Admin.Services.User;
 
 namespace ZhonTai.Admin.Core;
 
@@ -167,7 +168,7 @@ public class HostApp
 
         //用户信息
         services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
-        services.TryAddSingleton<IUser, User>();
+        services.TryAddScoped<IUser, User>();
 
         //数据库配置
         var dbConfig = ConfigHelper.Get<DbConfig>("dbconfig", env.EnvironmentName);
@@ -178,10 +179,9 @@ public class HostApp
         services.AddSingleton<IFreeSql>(freeSqlCloud);
         services.AddSingleton(freeSqlCloud);
         services.AddScoped<UnitOfWorkManagerCloud>();
-        services.AddAdminDb(freeSqlCloud, env, _hostAppOptions);
+        services.AddMasterDb(freeSqlCloud, env, _hostAppOptions);
         services.AddSingleton(provider => freeSqlCloud.Use(DbKeys.MasterDb));
 
-
         //上传配置
         var uploadConfig = ConfigHelper.Load("uploadconfig", env.EnvironmentName, true);
         services.Configure<UploadConfig>(uploadConfig);
@@ -431,7 +431,7 @@ public class HostApp
                 options.Conventions.Add(new ApiGroupConvention());
             }
         }
-        
+
         var mvcBuilder = appConfig.AppType switch
         {
             AppType.Controllers => services.AddControllers(controllersAction),
@@ -440,7 +440,7 @@ public class HostApp
             _ => services.AddControllers(controllersAction)
         };
 
-        foreach(var assembly in assemblies)
+        foreach (var assembly in assemblies)
         {
             services.AddValidatorsFromAssembly(assembly);
         }
@@ -562,6 +562,19 @@ public class HostApp
         //授权
         app.UseAuthorization();
 
+        //初始化会话数据权限
+        app.Use(async (ctx, next) =>
+        {
+            var user = ctx.RequestServices.GetRequiredService<IUser>();
+            if (user?.Id > 0)
+            {
+                var userService = ctx.RequestServices.GetRequiredService<IUserService>();
+                await userService.GetDataPermissionAsync();
+            }
+
+            await next();
+        });
+
         //配置端点
         app.UseEndpoints(endpoints =>
         {

+ 1 - 1
src/platform/ZhonTai.Admin/Domain/User/Dto/CurrentUserDto.cs → src/platform/ZhonTai.Admin/Domain/User/Dto/DataPermissionDto.cs

@@ -3,7 +3,7 @@ using ZhonTai.Admin.Domain.Role;
 
 namespace ZhonTai.Admin.Domain.User.Dto;
 
-public class CurrentUserDto
+public class DataPermissionDto
 {
     /// <summary>
     /// 部门Id

+ 2 - 4
src/platform/ZhonTai.Admin/Domain/User/IUserRepository.cs

@@ -1,10 +1,8 @@
-using System.Threading.Tasks;
-using ZhonTai.Admin.Core.Repositories;
-using ZhonTai.Admin.Domain.User.Dto;
+using ZhonTai.Admin.Core.Repositories;
 
 namespace ZhonTai.Admin.Domain.User;
 
 public interface IUserRepository : IRepositoryBase<UserEntity>
 {
-    Task<CurrentUserDto> GetCurrentUserAsync();
+    
 }

+ 4 - 4
src/platform/ZhonTai.Admin/Domain/User/UserEntity.cs

@@ -20,14 +20,14 @@ public partial class UserEntity : EntityBase, ITenant, IData
     /// <summary>
     /// 拥有者Id
     /// </summary>
-    [Column(Position = -23)]
+    [Column(Position = -24)]
     public long? OwnerId { get; set; }
 
     /// <summary>
-    /// 创建者部门Id
+    /// 拥有者部门Id
     /// </summary>
-    [Column(Position = -23, CanUpdate = false)]
-    public long? CreatedOrgId { get; set; }
+    [Column(Position = -23)]
+    public long? OwnerOrgId { get; set; }
 
     /// <summary>
     /// 租户Id

+ 2 - 86
src/platform/ZhonTai.Admin/Repositories/User/UserRepository.cs

@@ -1,97 +1,13 @@
-using Microsoft.AspNetCore.Mvc;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using ZhonTai.Admin.Core.Db.Transaction;
+using ZhonTai.Admin.Core.Db.Transaction;
 using ZhonTai.Admin.Core.Repositories;
-using ZhonTai.Admin.Domain;
-using ZhonTai.Admin.Domain.Org;
-using ZhonTai.Admin.Domain.Role;
 using ZhonTai.Admin.Domain.User;
-using ZhonTai.Admin.Domain.User.Dto;
 
 namespace ZhonTai.Admin.Repositories;
 
 public class UserRepository : RepositoryBase<UserEntity>, IUserRepository
 {
-    private readonly IOrgRepository _orgRepository;
-    private readonly IRepositoryBase<RoleOrgEntity> _roleOrgRepository;
-    public UserRepository(
-        UnitOfWorkManagerCloud muowm, 
-        IOrgRepository orgRepository, 
-        IRepositoryBase<RoleOrgEntity> roleOrgRepository
-    ) : base(muowm)
+    public UserRepository(UnitOfWorkManagerCloud muowm) : base(muowm)
     {
-        _orgRepository = orgRepository;
-        _roleOrgRepository = roleOrgRepository;
-    }
-
-    /// <summary>
-    /// 获得当前登录用户
-    /// </summary>
-    /// <returns></returns>
-    [NonAction]
-    public async Task<CurrentUserDto> GetCurrentUserAsync()
-    {
-        var user = await Select
-        .IncludeMany(a => a.Roles.Select(b => new RoleEntity
-        {
-            Id = b.Id,
-            DataScope = b.DataScope
-        }))
-        .WhereDynamic(User.Id)
-        .ToOneAsync(a => new
-        {
-            a.OrgId,
-            a.Roles
-        });
-
-        //数据范围
-        DataScope dataScope = DataScope.Self;
-        var customRoleIds = new List<long>();
-        user.Roles?.ToList().ForEach(role =>
-        {
-            if (role.DataScope == DataScope.Custom)
-            {
-                customRoleIds.Add(role.Id);
-            }
-            else if (role.DataScope <= dataScope)
-            {
-                dataScope = role.DataScope;
-            }
-        });
-
-        //部门列表
-        var orgIds = new List<long>();
-        if (dataScope != DataScope.All)
-        {
-            //本部门
-            if (dataScope == DataScope.Dept)
-            {
-                orgIds.Add(user.OrgId);
-            }
-            //本部门和下级部门
-            else if (dataScope == DataScope.DeptWithChild)
-            {
-                orgIds = await _orgRepository
-                .Where(a => a.Id == user.OrgId)
-                .AsTreeCte()
-                .ToListAsync(a => a.Id);
-            }
-
-            //指定部门
-            if (customRoleIds.Count > 0)
-            {
-                var customRoleOrgIds = await _roleOrgRepository.Select.Where(a => customRoleIds.Contains(a.RoleId)).ToListAsync(a => a.OrgId);
-                orgIds = orgIds.Concat(customRoleOrgIds).ToList();
-            }
-        }
 
-        return new CurrentUserDto
-        {
-            OrgId = user.OrgId,
-            OrgIds = orgIds.Distinct().ToList(),
-            DataScope = dataScope
-        };
     }
 }

+ 128 - 120
src/platform/ZhonTai.Admin/Services/Auth/AuthService.cs

@@ -34,6 +34,7 @@ using FreeSql;
 using Microsoft.Extensions.DependencyInjection;
 using ZhonTai.Admin.Domain.TenantPermission;
 using ZhonTai.Admin.Core.Db;
+using System.Collections.Generic;
 
 namespace ZhonTai.Admin.Services.Auth;
 
@@ -112,6 +113,8 @@ public class AuthService : BaseService, IAuthService, IDynamicApi
         return ResultOutput.Ok(data);
     }
 
+   
+
     /// <summary>
     /// 查询用户信息
     /// </summary>
@@ -124,72 +127,75 @@ public class AuthService : BaseService, IAuthService, IDynamicApi
             return ResultOutput.NotOk("未登录");
         }
 
-        var authGetUserInfoOutput = new AuthGetUserInfoOutput
-        {
-            //用户信息
-            User = await _userRepository.GetAsync<AuthUserProfileDto>(User.Id)
-        };
-
-        
-        IFreeSql db = _permissionRepository.Orm;
-        if (User.TenantAdmin)
+        using (_userRepository.DataFilter.Disable(FilterNames.Self, FilterNames.Data))
         {
-            var cloud = ServiceProvider.GetRequiredService<FreeSqlCloud>();
-            db = cloud.Use(DbKeys.MasterDb);
-        }
-       
-        var permissionRepository = db.GetRepositoryBase<PermissionEntity>();
-        var menuSelect = permissionRepository.Select;
+            var authGetUserInfoOutput = new AuthGetUserInfoOutput
+            {
+                //用户信息
+                User = await _userRepository.GetAsync<AuthUserProfileDto>(User.Id)
+            };
 
-        var dotSelect = permissionRepository.Select.Where(a => a.Type == PermissionType.Dot);
 
-        if (!User.PlatformAdmin)
-        {
+            IFreeSql db = _permissionRepository.Orm;
             if (User.TenantAdmin)
             {
-                menuSelect = menuSelect.Where(a =>
-                   db.Select<TenantPermissionEntity>()
-                   .Where(b => b.PermissionId == a.Id && b.TenantId == User.TenantId)
-                   .Any()
-               );
-
-                dotSelect = dotSelect.Where(a =>
-                   db.Select<TenantPermissionEntity>()
-                   .Where(b => b.PermissionId == a.Id && b.TenantId == User.TenantId)
-                   .Any()
-                );
+                var cloud = ServiceProvider.GetRequiredService<FreeSqlCloud>();
+                db = cloud.Use(DbKeys.MasterDb);
             }
-            else
+
+            var permissionRepository = db.GetRepositoryBase<PermissionEntity>();
+            var menuSelect = permissionRepository.Select;
+
+            var dotSelect = permissionRepository.Select.Where(a => a.Type == PermissionType.Dot);
+
+            if (!User.PlatformAdmin)
             {
-                menuSelect = menuSelect.Where(a =>
-                   db.Select<RolePermissionEntity>()
-                   .InnerJoin<UserRoleEntity>((b, c) => b.RoleId == c.RoleId && c.UserId == User.Id)
-                   .Where(b => b.PermissionId == a.Id)
-                   .Any()
-               );
-
-                dotSelect = dotSelect.Where(a =>
-                    db.Select<RolePermissionEntity>()
-                    .InnerJoin<UserRoleEntity>((b, c) => b.RoleId == c.RoleId && c.UserId == User.Id)
-                    .Where(b => b.PermissionId == a.Id)
-                    .Any()
-                );
-            }
+                if (User.TenantAdmin)
+                {
+                    menuSelect = menuSelect.Where(a =>
+                       db.Select<TenantPermissionEntity>()
+                       .Where(b => b.PermissionId == a.Id && b.TenantId == User.TenantId)
+                       .Any()
+                   );
+
+                    dotSelect = dotSelect.Where(a =>
+                       db.Select<TenantPermissionEntity>()
+                       .Where(b => b.PermissionId == a.Id && b.TenantId == User.TenantId)
+                       .Any()
+                    );
+                }
+                else
+                {
+                    menuSelect = menuSelect.Where(a =>
+                       db.Select<RolePermissionEntity>()
+                       .InnerJoin<UserRoleEntity>((b, c) => b.RoleId == c.RoleId && c.UserId == User.Id)
+                       .Where(b => b.PermissionId == a.Id)
+                       .Any()
+                   );
+
+                    dotSelect = dotSelect.Where(a =>
+                        db.Select<RolePermissionEntity>()
+                        .InnerJoin<UserRoleEntity>((b, c) => b.RoleId == c.RoleId && c.UserId == User.Id)
+                        .Where(b => b.PermissionId == a.Id)
+                        .Any()
+                    );
+                }
 
-            menuSelect = menuSelect.AsTreeCte(up: true);
-        }
+                menuSelect = menuSelect.AsTreeCte(up: true);
+            }
 
-        var menuList = await menuSelect
-            .Where(a => new[] { PermissionType.Group, PermissionType.Menu }.Contains(a.Type))
-            .ToListAsync(a => new AuthUserMenuDto { ViewPath = a.View.Path });
+            var menuList = await menuSelect
+                .Where(a => new[] { PermissionType.Group, PermissionType.Menu }.Contains(a.Type))
+                .ToListAsync(a => new AuthUserMenuDto { ViewPath = a.View.Path });
 
-        //用户菜单
-        authGetUserInfoOutput.Menus = menuList.DistinctBy(a => a.Id).OrderBy(a => a.ParentId).ThenBy(a => a.Sort).ToList();
+            //用户菜单
+            authGetUserInfoOutput.Menus = menuList.DistinctBy(a => a.Id).OrderBy(a => a.ParentId).ThenBy(a => a.Sort).ToList();
 
-        //用户权限点
-        authGetUserInfoOutput.Permissions = await dotSelect.ToListAsync(a => a.Code);
+            //用户权限点
+            authGetUserInfoOutput.Permissions = await dotSelect.ToListAsync(a => a.Code);
 
-        return ResultOutput.Ok(authGetUserInfoOutput);
+            return ResultOutput.Ok(authGetUserInfoOutput);
+        }
     }
 
     /// <summary>
@@ -202,94 +208,96 @@ public class AuthService : BaseService, IAuthService, IDynamicApi
     [NoOprationLog]
     public async Task<IResultOutput> LoginAsync(AuthLoginInput input)
     {
-        var sw = new Stopwatch();
-        sw.Start();
+        using (_userRepository.DataFilter.Disable(FilterNames.Tenant, FilterNames.Self, FilterNames.Data))
+        {
+            var sw = new Stopwatch();
+            sw.Start();
 
-        #region 验证码校验
+            #region 验证码校验
 
-        if (_appConfig.VarifyCode.Enable)
-        {
-            input.Captcha.DeleteCache = true;
-            input.Captcha.CaptchaKey = CacheKeys.Captcha;
-            var isOk = await _captchaTool.CheckAsync(input.Captcha);
-            if (!isOk)
+            if (_appConfig.VarifyCode.Enable)
             {
-                return ResultOutput.NotOk("安全验证不通过,请重新登录");
+                input.Captcha.DeleteCache = true;
+                input.Captcha.CaptchaKey = CacheKeys.Captcha;
+                var isOk = await _captchaTool.CheckAsync(input.Captcha);
+                if (!isOk)
+                {
+                    return ResultOutput.NotOk("安全验证不通过,请重新登录");
+                }
             }
-        }
 
-        #endregion
+            #endregion
 
-        #region 密码解密
+            #region 密码解密
 
-        if (input.PasswordKey.NotNull())
-        {
-            var passwordEncryptKey = CacheKeys.PassWordEncrypt + input.PasswordKey;
-            var existsPasswordKey = await Cache.ExistsAsync(passwordEncryptKey);
-            if (existsPasswordKey)
+            if (input.PasswordKey.NotNull())
             {
-                var secretKey = await Cache.GetAsync(passwordEncryptKey);
-                if (secretKey.IsNull())
+                var passwordEncryptKey = CacheKeys.PassWordEncrypt + input.PasswordKey;
+                var existsPasswordKey = await Cache.ExistsAsync(passwordEncryptKey);
+                if (existsPasswordKey)
                 {
-                    return ResultOutput.NotOk("解密失败");
+                    var secretKey = await Cache.GetAsync(passwordEncryptKey);
+                    if (secretKey.IsNull())
+                    {
+                        return ResultOutput.NotOk("解密失败");
+                    }
+                    input.Password = DesEncrypt.Decrypt(input.Password, secretKey);
+                    await Cache.DelAsync(passwordEncryptKey);
+                }
+                else
+                {
+                    return ResultOutput.NotOk("解密失败!");
                 }
-                input.Password = DesEncrypt.Decrypt(input.Password, secretKey);
-                await Cache.DelAsync(passwordEncryptKey);
-            }
-            else
-            {
-                return ResultOutput.NotOk("解密失败!");
             }
-        }
 
-        #endregion
+            #endregion
 
-        #region 登录
-        var password = MD5Encrypt.Encrypt32(input.Password);
-        var user = await _userRepository.Select.DisableGlobalFilter(FilterNames.Tenant)
-            .Where(a => a.UserName == input.UserName && a.Password == password).ToOneAsync();
+            #region 登录
+            var password = MD5Encrypt.Encrypt32(input.Password);
+            var user = await _userRepository.Select.Where(a => a.UserName == input.UserName && a.Password == password).ToOneAsync();
 
-        if (!(user?.Id > 0))
-        {
-            return ResultOutput.NotOk("用户名或密码错误");
-        }
+            if (!(user?.Id > 0))
+            {
+                return ResultOutput.NotOk("用户名或密码错误");
+            }
 
-        if(user.Status== UserStatus.Disabled)
-        {
-            return ResultOutput.NotOk("禁止登录,请联系管理员");
-        }
-        #endregion
+            if (user.Status == UserStatus.Disabled)
+            {
+                return ResultOutput.NotOk("禁止登录,请联系管理员");
+            }
+            #endregion
 
-        #region 获得token
-        var authLoginOutput = Mapper.Map<AuthLoginOutput>(user);
-        if (_appConfig.Tenant)
-        {
-            var tenant = await _tenantRepository.Select.DisableGlobalFilter(FilterNames.Tenant).WhereDynamic(user.TenantId).ToOneAsync(a => new { a.TenantType, a.DbKey });
-            authLoginOutput.TenantType = tenant.TenantType;
-            authLoginOutput.DbKey = tenant.DbKey;
-        }
-        string token = GetToken(authLoginOutput); 
-        #endregion
+            #region 获得token
+            var authLoginOutput = Mapper.Map<AuthLoginOutput>(user);
+            if (_appConfig.Tenant)
+            {
+                var tenant = await _tenantRepository.Select.WhereDynamic(user.TenantId).ToOneAsync(a => new { a.TenantType, a.DbKey });
+                authLoginOutput.TenantType = tenant.TenantType;
+                authLoginOutput.DbKey = tenant.DbKey;
+            }
+            string token = GetToken(authLoginOutput);
+            #endregion
 
-        sw.Stop();
+            sw.Stop();
 
-        #region 添加登录日志
+            #region 添加登录日志
 
-        var loginLogAddInput = new LoginLogAddInput
-        {
-            TenantId = authLoginOutput.TenantId,
-            Name = authLoginOutput.Name,
-            ElapsedMilliseconds = sw.ElapsedMilliseconds,
-            Status = true,
-            CreatedUserId = authLoginOutput.Id,
-            CreatedUserName = input.UserName,
-        };
+            var loginLogAddInput = new LoginLogAddInput
+            {
+                TenantId = authLoginOutput.TenantId,
+                Name = authLoginOutput.Name,
+                ElapsedMilliseconds = sw.ElapsedMilliseconds,
+                Status = true,
+                CreatedUserId = authLoginOutput.Id,
+                CreatedUserName = input.UserName,
+            };
 
-        await LazyGetRequiredService<ILoginLogService>().AddAsync(loginLogAddInput);
+            await LazyGetRequiredService<ILoginLogService>().AddAsync(loginLogAddInput);
 
-        #endregion 添加登录日志
+            #endregion 添加登录日志
 
-        return ResultOutput.Ok(new { token });
+            return ResultOutput.Ok(new { token });
+        }
     }
 
     /// <summary>

+ 1 - 1
src/platform/ZhonTai.Admin/Services/Cache/CacheService.cs

@@ -69,7 +69,7 @@ public class CacheService : BaseService, ICacheService, IDynamicApi
     public async Task<IResultOutput> ClearAsync(string cacheKey)
     {
         Logger.LogWarning($"{User.Id}.{User.UserName}清除缓存[{cacheKey}]");
-        await Cache.DelByPatternAsync(cacheKey);
+        await Cache.DelByPatternAsync(cacheKey + "*");
         return ResultOutput.Ok();
     }
 }

+ 10 - 0
src/platform/ZhonTai.Admin/Services/Org/OrgService.cs

@@ -9,6 +9,7 @@ using ZhonTai.DynamicApi;
 using ZhonTai.Admin.Core.Repositories;
 using ZhonTai.Admin.Domain;
 using ZhonTai.Admin.Core.Attributes;
+using ZhonTai.Admin.Core.Auth;
 
 namespace ZhonTai.Admin.Services.Org;
 
@@ -73,6 +74,8 @@ public class OrgService : BaseService, IOrgService, IDynamicApi
 
         var dictionary = Mapper.Map<OrgEntity>(input);
         var id = (await _orgRepository.InsertAsync(dictionary)).Id;
+        await Cache.DelByPatternAsync(CacheKeys.DataPermission + "*");
+
         return ResultOutput.Result(id > 0);
     }
 
@@ -117,6 +120,9 @@ public class OrgService : BaseService, IOrgService, IDynamicApi
 
         Mapper.Map(input, entity);
         await _orgRepository.UpdateAsync(entity);
+
+        await Cache.DelByPatternAsync(CacheKeys.DataPermission + "*");
+
         return ResultOutput.Ok();
     }
 
@@ -147,6 +153,8 @@ public class OrgService : BaseService, IOrgService, IDynamicApi
         //删除本部门和下级部门
         await _orgRepository.DeleteAsync(a => orgIdList.Contains(a.Id));
 
+        await Cache.DelByPatternAsync(CacheKeys.DataPermission + "*");
+
         return ResultOutput.Ok();
     }
 
@@ -177,6 +185,8 @@ public class OrgService : BaseService, IOrgService, IDynamicApi
         //删除本部门和下级部门
         await _orgRepository.SoftDeleteAsync(a => orgIdList.Contains(a.Id));
 
+        await Cache.DelByPatternAsync(CacheKeys.DataPermission + "*");
+
         return ResultOutput.Ok();
     }
 }

+ 42 - 2
src/platform/ZhonTai.Admin/Services/Role/RoleService.cs

@@ -15,6 +15,8 @@ using ZhonTai.Admin.Domain.UserRole;
 using ZhonTai.Admin.Domain.User;
 using ZhonTai.Admin.Domain;
 using ZhonTai.Admin.Domain.Org;
+using Org.BouncyCastle.Crypto;
+using ZhonTai.Admin.Core.Entities;
 
 namespace ZhonTai.Admin.Services.Role;
 
@@ -132,6 +134,12 @@ public class RoleService : BaseService, IRoleService, IDynamicApi
             await _userRoleRepository.InsertAsync(userRoleList);
         }
 
+        var clearUserIds = userIds.Concat(input.UserIds).Distinct();
+        foreach (var userId in clearUserIds)
+        {
+            await Cache.DelAsync(CacheKeys.DataPermission + userId);
+        }
+
         return ResultOutput.Ok();
     }
 
@@ -149,6 +157,11 @@ public class RoleService : BaseService, IRoleService, IDynamicApi
             await _userRoleRepository.Where(a => a.RoleId == input.RoleId && input.UserIds.Contains(a.UserId)).ToDelete().ExecuteAffrowsAsync();
         }
 
+        foreach (var userId in userIds)
+        {
+            await Cache.DelAsync(CacheKeys.DataPermission + userId);
+        }
+
         return ResultOutput.Ok();
     }
 
@@ -234,6 +247,12 @@ public class RoleService : BaseService, IRoleService, IDynamicApi
             await AddRoleOrgAsync(entity.Id, input.OrgIds);
         }
 
+        var userIds = await _userRoleRepository.Select.Where(a => a.RoleId == entity.Id).ToListAsync(a => a.UserId);
+        foreach (var userId in userIds)
+        {
+            await Cache.DelAsync(CacheKeys.DataPermission + userId);
+        }
+
         return ResultOutput.Ok();
     }
 
@@ -245,12 +264,19 @@ public class RoleService : BaseService, IRoleService, IDynamicApi
     [Transaction]
     public virtual async Task<IResultOutput> DeleteAsync(long id)
     {
+        var userIds = await _userRoleRepository.Select.Where(a => a.RoleId == id).ToListAsync(a => a.UserId);
+
         //删除用户角色
         await _userRoleRepository.DeleteAsync(a => a.UserId == id);
         //删除角色权限
         await _rolePermissionRepository.DeleteAsync(a => a.RoleId == id);
         //删除角色
         await _roleRepository.DeleteAsync(m => m.Id == id);
+        
+        foreach (var userId in userIds)
+        {
+            await Cache.DelAsync(CacheKeys.DataPermission + userId);
+        }
 
         return ResultOutput.Ok();
     }
@@ -263,6 +289,7 @@ public class RoleService : BaseService, IRoleService, IDynamicApi
     [Transaction]
     public virtual async Task<IResultOutput> BatchDeleteAsync(long[] ids)
     {
+        var userIds = await _userRoleRepository.Select.Where(a => ids.Contains(a.RoleId)).ToListAsync(a => a.UserId);
         //删除用户角色
         await _userRoleRepository.DeleteAsync(a => ids.Contains(a.RoleId));
         //删除角色权限
@@ -270,6 +297,11 @@ public class RoleService : BaseService, IRoleService, IDynamicApi
         //删除角色
         await _roleRepository.DeleteAsync(a => ids.Contains(a.Id));
 
+        foreach (var userId in userIds)
+        {
+            await Cache.DelAsync(CacheKeys.DataPermission + userId);
+        }
+
         return ResultOutput.Ok();
     }
 
@@ -281,10 +313,14 @@ public class RoleService : BaseService, IRoleService, IDynamicApi
     [Transaction]
     public virtual async Task<IResultOutput> SoftDeleteAsync(long id)
     {
+        var userIds = await _userRoleRepository.Select.Where(a => a.RoleId == id).ToListAsync(a => a.UserId);
         await _userRoleRepository.DeleteAsync(a => a.RoleId == id);
         await _rolePermissionRepository.DeleteAsync(a => a.RoleId == id);
         await _roleRepository.SoftDeleteAsync(id);
-
+        foreach (var userId in userIds)
+        {
+            await Cache.DelAsync(CacheKeys.DataPermission + userId);
+        }
         return ResultOutput.Ok();
     }
 
@@ -296,10 +332,14 @@ public class RoleService : BaseService, IRoleService, IDynamicApi
     [Transaction]
     public virtual async Task<IResultOutput> BatchSoftDeleteAsync(long[] ids)
     {
+        var userIds = await _userRoleRepository.Select.Where(a => ids.Contains(a.RoleId)).ToListAsync(a => a.UserId);
         await _userRoleRepository.DeleteAsync(a => ids.Contains(a.RoleId));
         await _rolePermissionRepository.DeleteAsync(a => ids.Contains(a.RoleId));
         await _roleRepository.SoftDeleteAsync(ids);
-
+        foreach (var userId in userIds)
+        {
+            await Cache.DelAsync(CacheKeys.DataPermission + userId);
+        }
         return ResultOutput.Ok();
     }
 }

+ 4 - 2
src/platform/ZhonTai.Admin/Services/User/IUserService.cs

@@ -12,12 +12,14 @@ namespace ZhonTai.Admin.Services.User;
 /// </summary>
 public interface IUserService
 {
-    Task<ResultOutput<AuthLoginOutput>> GetLoginUserAsync(long id);
-
     Task<IResultOutput> GetAsync(long id);
 
     Task<IResultOutput> GetPageAsync(PageInput<long?> input);
 
+    Task<ResultOutput<AuthLoginOutput>> GetLoginUserAsync(long id);
+
+    Task<DataPermissionDto> GetDataPermissionAsync();
+
     Task<IResultOutput> AddAsync(UserAddInput input);
 
     Task<IResultOutput> UpdateAsync(UserUpdateInput input);

+ 101 - 0
src/platform/ZhonTai.Admin/Services/User/UserService.cs

@@ -121,6 +121,7 @@ public class UserService : BaseService, IUserService, IDynamicApi
     /// </summary>
     /// <param name="id"></param>
     /// <returns></returns>
+    [NonAction]
     public async Task<ResultOutput<AuthLoginOutput>> GetLoginUserAsync(long id)
     {
         var output = new ResultOutput<AuthLoginOutput>();
@@ -137,6 +138,90 @@ public class UserService : BaseService, IUserService, IDynamicApi
         return output.Ok(entityDto);
     }
 
+    /// <summary>
+    /// 获得数据权限
+    /// </summary>
+    /// <returns></returns>
+    [NonAction]
+    public async Task<DataPermissionDto> GetDataPermissionAsync()
+    {
+        if (!(User?.Id > 0))
+        {
+            return null;
+        }
+
+        var key = CacheKeys.DataPermission + User.Id;
+        return await Cache.GetOrSetAsync(key, async () =>
+        {
+            using (_userRepository.DataFilter.Disable(FilterNames.Self, FilterNames.Data))
+            {
+                var user = await _userRepository.Select
+                .IncludeMany(a => a.Roles.Select(b => new RoleEntity
+                {
+                    Id = b.Id,
+                    DataScope = b.DataScope
+                }))
+                .WhereDynamic(User.Id)
+                .ToOneAsync(a => new
+                {
+                    a.OrgId,
+                    a.Roles
+                });
+
+                if (user == null)
+                    return null;
+
+                //数据范围
+                DataScope dataScope = DataScope.Self;
+                var customRoleIds = new List<long>();
+                user.Roles?.ToList().ForEach(role =>
+                {
+                    if (role.DataScope == DataScope.Custom)
+                    {
+                        customRoleIds.Add(role.Id);
+                    }
+                    else if (role.DataScope <= dataScope)
+                    {
+                        dataScope = role.DataScope;
+                    }
+                });
+
+                //部门列表
+                var orgIds = new List<long>();
+                if (dataScope != DataScope.All)
+                {
+                    //本部门
+                    if (dataScope == DataScope.Dept)
+                    {
+                        orgIds.Add(user.OrgId);
+                    }
+                    //本部门和下级部门
+                    else if (dataScope == DataScope.DeptWithChild)
+                    {
+                        orgIds = await _orgRepository
+                        .Where(a => a.Id == user.OrgId)
+                        .AsTreeCte()
+                        .ToListAsync(a => a.Id);
+                    }
+
+                    //指定部门
+                    if (customRoleIds.Count > 0)
+                    {
+                        var customRoleOrgIds = await _roleOrgRepository.Select.Where(a => customRoleIds.Contains(a.RoleId)).ToListAsync(a => a.OrgId);
+                        orgIds = orgIds.Concat(customRoleOrgIds).ToList();
+                    }
+                }
+
+                return new DataPermissionDto
+                {
+                    OrgId = user.OrgId,
+                    OrgIds = orgIds.Distinct().ToList(),
+                    DataScope = dataScope
+                };
+            }
+        });
+    }
+
     /// <summary>
     /// 查询用户基本信息
     /// </summary>
@@ -322,6 +407,8 @@ public class UserService : BaseService, IUserService, IDynamicApi
             await _userOrgRepository.InsertAsync(orgs);
         }
 
+        await Cache.DelAsync(CacheKeys.DataPermission + user.Id);
+
         return ResultOutput.Ok();
     }
 
@@ -394,6 +481,8 @@ public class UserService : BaseService, IUserService, IDynamicApi
         //删除用户
         await _userRepository.DeleteAsync(a => a.Id == id);
 
+        await Cache.DelAsync(CacheKeys.DataPermission + id);
+
         return ResultOutput.Ok();
     }
 
@@ -422,6 +511,11 @@ public class UserService : BaseService, IUserService, IDynamicApi
         //删除用户
         await _userRepository.DeleteAsync(a => ids.Contains(a.Id));
 
+        foreach (var userId in ids)
+        {
+            await Cache.DelAsync(CacheKeys.DataPermission + userId);
+        }
+
         return ResultOutput.Ok();
     }
 
@@ -449,6 +543,8 @@ public class UserService : BaseService, IUserService, IDynamicApi
         await _staffRepository.SoftDeleteAsync(a => a.Id == id);
         await _userRepository.SoftDeleteAsync(id);
 
+        await Cache.DelAsync(CacheKeys.DataPermission + id);
+
         return ResultOutput.Ok();
     }
 
@@ -473,6 +569,11 @@ public class UserService : BaseService, IUserService, IDynamicApi
         await _staffRepository.SoftDeleteAsync(a => ids.Contains(a.Id));
         await _userRepository.SoftDeleteAsync(ids);
 
+        foreach (var userId in ids)
+        {
+            await Cache.DelAsync(CacheKeys.DataPermission + userId);
+        }
+
         return ResultOutput.Ok();
     }
 

+ 31 - 20
src/platform/ZhonTai.Admin/ZhonTai.Admin.xml

@@ -162,9 +162,9 @@
             数据库注册键
             </summary>
         </member>
-        <member name="P:ZhonTai.Admin.Core.Auth.IUser.CurrentUser">
+        <member name="P:ZhonTai.Admin.Core.Auth.IUser.DataPermission">
             <summary>
-            当前用户
+            数据权限
             </summary>
         </member>
         <member name="T:ZhonTai.Admin.Core.Auth.PermissionHandler">
@@ -240,9 +240,15 @@
             数据库注册键
             </summary>
         </member>
-        <member name="P:ZhonTai.Admin.Core.Auth.User.CurrentUser">
+        <member name="M:ZhonTai.Admin.Core.Auth.User.GetDataPermission">
             <summary>
-            当前用户
+            获得数据权限
+            </summary>
+            <returns></returns>
+        </member>
+        <member name="P:ZhonTai.Admin.Core.Auth.User.DataPermission">
+            <summary>
+            数据权限
             </summary>
         </member>
         <member name="T:ZhonTai.Admin.Core.BaseController">
@@ -690,9 +696,9 @@
             用户权限 admin:user:permissions:用户主键
             </summary>
         </member>
-        <member name="F:ZhonTai.Admin.Core.Consts.CacheKeys.UserInfo">
+        <member name="F:ZhonTai.Admin.Core.Consts.CacheKeys.DataPermission">
             <summary>
-            用户信息 admin:user:info:用户主键
+            数据权限 admin:user:data:permission:用户主键
             </summary>
         </member>
         <member name="T:ZhonTai.Admin.Core.Consts.DbKeys">
@@ -730,6 +736,11 @@
             租户
             </summary>
         </member>
+        <member name="F:ZhonTai.Admin.Core.Consts.FilterNames.Self">
+            <summary>
+            本人权限
+            </summary>
+        </member>
         <member name="F:ZhonTai.Admin.Core.Consts.FilterNames.Data">
             <summary>
             数据权限
@@ -832,7 +843,7 @@
             <returns></returns>
             <exception cref="T:System.Exception"></exception>
         </member>
-        <member name="M:ZhonTai.Admin.Core.Db.DBServiceCollectionExtensions.AddAdminDb(Microsoft.Extensions.DependencyInjection.IServiceCollection,FreeSql.FreeSqlCloud,Microsoft.Extensions.Hosting.IHostEnvironment,ZhonTai.Admin.Core.Startup.HostAppOptions)">
+        <member name="M:ZhonTai.Admin.Core.Db.DBServiceCollectionExtensions.AddMasterDb(Microsoft.Extensions.DependencyInjection.IServiceCollection,FreeSql.FreeSqlCloud,Microsoft.Extensions.Hosting.IHostEnvironment,ZhonTai.Admin.Core.Startup.HostAppOptions)">
             <summary>
             添加主数据库
             </summary>
@@ -1240,9 +1251,9 @@
             拥有者Id
             </summary>
         </member>
-        <member name="P:ZhonTai.Admin.Core.Entities.IData.CreatedOrgId">
+        <member name="P:ZhonTai.Admin.Core.Entities.IData.OwnerOrgId">
             <summary>
-            创建者部门Id
+            拥有者部门Id
             </summary>
         </member>
         <member name="T:ZhonTai.Admin.Core.Entities.IDelete">
@@ -2670,17 +2681,17 @@
             个人简介
             </summary>
         </member>
-        <member name="P:ZhonTai.Admin.Domain.User.Dto.CurrentUserDto.OrgId">
+        <member name="P:ZhonTai.Admin.Domain.User.Dto.DataPermissionDto.OrgId">
             <summary>
             部门Id
             </summary>
         </member>
-        <member name="P:ZhonTai.Admin.Domain.User.Dto.CurrentUserDto.OrgIds">
+        <member name="P:ZhonTai.Admin.Domain.User.Dto.DataPermissionDto.OrgIds">
             <summary>
             部门列表
             </summary>
         </member>
-        <member name="P:ZhonTai.Admin.Domain.User.Dto.CurrentUserDto.DataScope">
+        <member name="P:ZhonTai.Admin.Domain.User.Dto.DataPermissionDto.DataScope">
             <summary>
             数据范围
             </summary>
@@ -2695,9 +2706,9 @@
             拥有者Id
             </summary>
         </member>
-        <member name="P:ZhonTai.Admin.Domain.User.UserEntity.CreatedOrgId">
+        <member name="P:ZhonTai.Admin.Domain.User.UserEntity.OwnerOrgId">
             <summary>
-            创建者部门Id
+            拥有者部门Id
             </summary>
         </member>
         <member name="P:ZhonTai.Admin.Domain.User.UserEntity.TenantId">
@@ -2951,12 +2962,6 @@
             <param name="idList"></param>
             <returns></returns>
         </member>
-        <member name="M:ZhonTai.Admin.Repositories.UserRepository.GetCurrentUserAsync">
-            <summary>
-            获得当前登录用户
-            </summary>
-            <returns></returns>
-        </member>
         <member name="T:ZhonTai.Admin.Services.Api.ApiService">
             <summary>
             接口服务
@@ -5723,6 +5728,12 @@
             <param name="id"></param>
             <returns></returns>
         </member>
+        <member name="M:ZhonTai.Admin.Services.User.UserService.GetDataPermissionAsync">
+            <summary>
+            获得数据权限
+            </summary>
+            <returns></returns>
+        </member>
         <member name="M:ZhonTai.Admin.Services.User.UserService.GetBasicAsync">
             <summary>
             查询用户基本信息