diff --git a/Yi.Furion.Net6/Yi.Framework.Infrastructure/Const/TokenTypeConst.cs b/Yi.Furion.Net6/Yi.Framework.Infrastructure/Const/TokenTypeConst.cs index 9e1e50fa..a594aa5f 100644 --- a/Yi.Furion.Net6/Yi.Framework.Infrastructure/Const/TokenTypeConst.cs +++ b/Yi.Furion.Net6/Yi.Framework.Infrastructure/Const/TokenTypeConst.cs @@ -14,6 +14,8 @@ namespace Yi.Framework.Infrastructure.Const public const string TenantId = nameof(TenantId); + public const string DeptId= nameof(DeptId); + public const string Email = nameof(Email); public const string PhoneNumber = nameof(PhoneNumber); diff --git a/Yi.Furion.Net6/Yi.Framework.Infrastructure/CurrentUsers/CurrentUser.cs b/Yi.Furion.Net6/Yi.Framework.Infrastructure/CurrentUsers/CurrentUser.cs index 17e6c9b2..da8bfa38 100644 --- a/Yi.Furion.Net6/Yi.Framework.Infrastructure/CurrentUsers/CurrentUser.cs +++ b/Yi.Furion.Net6/Yi.Framework.Infrastructure/CurrentUsers/CurrentUser.cs @@ -20,6 +20,9 @@ namespace Yi.Framework.Infrastructure.CurrentUsers public long Id => FindUserId(); + public long DeptId => FindDeptId(); + + public string UserName => this.FindClaimValue(TokenTypeConst.UserName); /// @@ -59,7 +62,21 @@ namespace Yi.Framework.Infrastructure.CurrentUsers return FindClaim(claimType)?.Value; } + public long FindDeptId() + { + var deptIdOrNull = _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == TokenTypeConst.DeptId); + if (deptIdOrNull == null || string.IsNullOrWhiteSpace(deptIdOrNull.Value)) + { + return 0; + } + if (long.TryParse(deptIdOrNull.Value, out long deptId)) + { + return deptId; + } + + return 0; + } public long FindUserId() { var userIdOrNull = _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == TokenTypeConst.Id); diff --git a/Yi.Furion.Net6/Yi.Framework.Infrastructure/CurrentUsers/ICurrentUser.cs b/Yi.Furion.Net6/Yi.Framework.Infrastructure/CurrentUsers/ICurrentUser.cs index 18485ed7..d8301545 100644 --- a/Yi.Furion.Net6/Yi.Framework.Infrastructure/CurrentUsers/ICurrentUser.cs +++ b/Yi.Furion.Net6/Yi.Framework.Infrastructure/CurrentUsers/ICurrentUser.cs @@ -11,6 +11,8 @@ namespace Yi.Framework.Infrastructure.CurrentUsers public bool IsAuthenticated { get; } public long Id { get; } + public long DeptId { get; } + public string UserName { get; } public Guid TenantId { get; } diff --git a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Domain/AccountManager.cs b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Domain/AccountManager.cs index 7e184f36..d74f568d 100644 --- a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Domain/AccountManager.cs +++ b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Domain/AccountManager.cs @@ -76,6 +76,10 @@ namespace Yi.Furion.Application.Rbac.Domain var claims = new Dictionary(); claims.Add(TokenTypeConst.Id, dto.User.Id); claims.Add(TokenTypeConst.UserName, dto.User.UserName); + if (dto.User.DeptId is not null) + { + claims.Add(TokenTypeConst.DeptId, dto.User.DeptId); + } if (dto.User.Email is not null) { claims.Add(TokenTypeConst.Email, dto.User.Email); diff --git a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/IAccountService.cs b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/IAccountService.cs new file mode 100644 index 00000000..3f73a407 --- /dev/null +++ b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/IAccountService.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Furion.Core.Rbac.Dtos; + +namespace Yi.Furion.Application.Rbac.Services +{ + public interface IAccountService + { + } +} diff --git a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/IDeptService.cs b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/IDeptService.cs index 496848c8..932819ff 100644 --- a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/IDeptService.cs +++ b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/IDeptService.cs @@ -9,5 +9,6 @@ namespace Yi.Furion.Application.Rbac.Services public interface IDeptService : ICrudAppService { Task> GetChildListAsync(long deptId); + Task> GetListRoleIdAsync([FromRoute] long roleId); } } diff --git a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/AccountService.cs b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/AccountService.cs index 0620b727..8ec75824 100644 --- a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/AccountService.cs +++ b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/AccountService.cs @@ -23,7 +23,7 @@ using Yi.Furion.Sqlsugar.Core.Repositories; namespace Yi.Furion.Application.Rbac.Services.Impl { - public class AccountService : ApplicationService, ITransient, IDynamicApiController + public class AccountService : ApplicationService, IAccountService, ITransient, IDynamicApiController { public AccountService(IUserRepository userRepository, ICurrentUser currentUser, AccountManager accountManager, IRepository menuRepository, SmsAliyunManager smsAliyunManager, IOptions smsAliyunManagerOptions, SecurityCodeHelper securityCode, IMemoryCache memoryCache, IEventPublisher eventPublisher, IHttpContextAccessor httpContextAccessor) => diff --git a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/DeptService.cs b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/DeptService.cs index 003785f8..42a38b6a 100644 --- a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/DeptService.cs +++ b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/DeptService.cs @@ -3,6 +3,7 @@ using Yi.Framework.Infrastructure.Ddd.Dtos; using Yi.Framework.Infrastructure.Ddd.Services; using Yi.Furion.Core.Rbac.Dtos.Dept; using Yi.Furion.Core.Rbac.Entities; +using Yi.Furion.Sqlsugar.Core.Repositories; namespace Yi.Furion.Application.Rbac.Services.Impl { @@ -12,11 +13,12 @@ namespace Yi.Furion.Application.Rbac.Services.Impl public class DeptService : CrudAppService, IDeptService, ITransient, IDynamicApiController { + private IDeptRepository _deptRepository; + public DeptService(IDeptRepository deptRepository) { _deptRepository = deptRepository; } [NonAction] public async Task> GetChildListAsync(long deptId) { - var entities= await _DbQueryable.ToChildListAsync(x=>x.ParentId,deptId); - return entities.Select(x => x.Id).ToList(); + return await _deptRepository.GetChildListAsync(deptId); } /// @@ -26,7 +28,7 @@ namespace Yi.Furion.Application.Rbac.Services.Impl //[Route("{roleId}")] public async Task> GetListRoleIdAsync([FromRoute] long roleId) { - var entities = await _DbQueryable.Where(d => SqlFunc.Subqueryable().Where(rd => rd.RoleId == roleId && d.Id == rd.DeptId).Any()).ToListAsync(); + var entities = await _deptRepository.GetListRoleIdAsync(roleId); return await MapToGetListOutputDtosAsync(entities); } diff --git a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/RoleService.cs b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/RoleService.cs index 76d1e6e4..0a8c946b 100644 --- a/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/RoleService.cs +++ b/Yi.Furion.Net6/Yi.Furion.Application/Rbac/Services/Impl/RoleService.cs @@ -24,14 +24,6 @@ namespace Yi.Furion.Application.Rbac.Services.Impl private IRepository _roleDeptRepository; - - public async Task> GetDeptIdsAsync(long roleId) - { - var entities = await _roleDeptRepository.GetListAsync(x => x.RoleId == roleId); - return entities.Select(x => x.DeptId).ToList(); - - } - [UnitOfWork] public async Task UpdateDataScpoceAsync(UpdateDataScpoceInput input) { diff --git a/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/Repositories/IDeptRepository.cs b/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/Repositories/IDeptRepository.cs new file mode 100644 index 00000000..5043da55 --- /dev/null +++ b/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/Repositories/IDeptRepository.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Yi.Furion.Core.Rbac.Entities; + +namespace Yi.Furion.Sqlsugar.Core.Repositories +{ + public interface IDeptRepository + { + Task> GetChildListAsync(long deptId); + Task> GetListRoleIdAsync([FromRoute] long roleId); + } +} diff --git a/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/Repositories/Impl/DeptRepository.cs b/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/Repositories/Impl/DeptRepository.cs new file mode 100644 index 00000000..f0aa4bac --- /dev/null +++ b/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/Repositories/Impl/DeptRepository.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Furion.DependencyInjection; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Yi.Framework.Infrastructure.Sqlsugar.Repositories; +using Yi.Furion.Core.Bbs.Entities; +using Yi.Furion.Core.Rbac.Dtos.Dept; +using Yi.Furion.Core.Rbac.Entities; + +namespace Yi.Furion.Sqlsugar.Core.Repositories.Impl +{ + public class DeptRepository : SqlsugarRepository, IDeptRepository, ITransient + { + public DeptRepository(ISqlSugarClient context) : base(context) + { + } + + public async Task> GetChildListAsync(long deptId) + { + var entities = await _DbQueryable.ToChildListAsync(x => x.ParentId, deptId); + return entities.Select(x => x.Id).ToList(); + } + public async Task> GetListRoleIdAsync([FromRoute] long roleId) + { + + return await _DbQueryable.Where(d => SqlFunc.Subqueryable().Where(rd => rd.RoleId == roleId && d.Id == rd.DeptId).Any()).ToListAsync(); + } + } +} diff --git a/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/Startup.cs b/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/Startup.cs index d79869ff..e3abcbae 100644 --- a/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/Startup.cs +++ b/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/Startup.cs @@ -1,5 +1,6 @@ using Furion; using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json.Schema; using Yi.Framework.Infrastructure.Sqlsugar; namespace Yi.Furion.Sqlsugar.Core; diff --git a/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/YiDbContext.cs b/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/YiDbContext.cs index ee085d8a..245bfaba 100644 --- a/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/YiDbContext.cs +++ b/Yi.Furion.Net6/Yi.Furion.Sqlsugar.Core/YiDbContext.cs @@ -1,13 +1,21 @@ using System; using System.Collections.Generic; +using System.Data; using System.Linq; +using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; +using Furion.LinqBuilder; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using SqlSugar; using Yi.Framework.Infrastructure.CurrentUsers; +using Yi.Framework.Infrastructure.Data.Filters; using Yi.Framework.Infrastructure.Sqlsugar; +using Yi.Furion.Core.Rbac.Consts; +using Yi.Furion.Core.Rbac.Entities; +using Yi.Furion.Core.Rbac.Enums; +using Yi.Furion.Sqlsugar.Core.Repositories; namespace Yi.Furion.Sqlsugar.Core { @@ -23,12 +31,29 @@ namespace Yi.Furion.Sqlsugar.Core //进行Aop数据权限过滤 protected override void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient) + { + //由于此处数据过滤为最底层,不能依赖仓储 + DataScopeFilter(sqlSugarClient); + } + + /// + /// 数据权限过滤 + /// + private async void DataScopeFilter(ISqlSugarClient sqlSugarClient) { //这里Aop进行数据权限过滤 var userId = _currentUser.Id; - if (userId == 0) return; - _logger.LogInformation($"用户【{userId}】访问Aop"); + var userName = _currentUser.UserName; + var deptId = _currentUser.DeptId; + //超管或者 + if (userId == 0 || UserConst.Admin.Equals(userName)) return; + //如果没有部门,只能看到自己 + if (deptId == 0) + { + sqlSugarClient.QueryFilter.AddTableFilter(x => x.Id == userId); + return; + } /* * 这里数据权限,步骤: * 1:获取用户id @@ -37,6 +62,50 @@ namespace Yi.Furion.Sqlsugar.Core * 4:会涉及部门表的筛选,所以还需要获取用户的所在部门,如果没有部门,那就是过滤到只看自己 * 5:可直接使用DB进行查询部门即可 */ + var roles = await sqlSugarClient.Queryable().Where(x => SqlFunc.Subqueryable().Where(ur =>ur.UserId == userId).Any()).ToListAsync(); + //获取到全部角色 + + Expression> expression = (x) => true; + + //添加数据过滤 + foreach (var role in roles.OrderBy(x => x.DataScope)) + { + switch (role.DataScope) + { + //全部数据权限,直接返回 + case DataScopeEnum.ALL: + return; + + + //自定义数据过滤 + case DataScopeEnum.CUSTOM: + var deptIds1 = (await sqlSugarClient.Queryable().Where(x => SqlFunc.Subqueryable().Where(ur => ur.RoleId == role.Id).Any()).ToListAsync()).Select(x => x.Id).ToList(); + expression.Or(x => deptIds1.Contains(x.DeptId ?? -1)); + break; + + + //部门数据过滤 + case DataScopeEnum.DEPT: + expression.Or(x => x.DeptId == deptId); + break; + + + //部门及一下数据过滤 + case DataScopeEnum.DEPT_FOLLOW: + var deptIds = ( await sqlSugarClient.Queryable().ToChildListAsync(x=>x.ParentId,deptId)).Select(x=>x.Id).ToList(); + expression.Or(x => deptIds.Contains(x.DeptId ?? -1)); + break; + + + //自己数据过滤 + case DataScopeEnum.USER: + expression.Or(x => x.Id == userId); + break; + default: + break; + } + sqlSugarClient.QueryFilter.AddTableFilter(expression); + } } } } diff --git a/Yi.Furion.Net6/Yi.Furion.Web.Core/Startup.cs b/Yi.Furion.Net6/Yi.Furion.Web.Core/Startup.cs index 310be1d7..2c20b346 100644 --- a/Yi.Furion.Net6/Yi.Furion.Web.Core/Startup.cs +++ b/Yi.Furion.Net6/Yi.Furion.Web.Core/Startup.cs @@ -39,7 +39,7 @@ public class Startup : AppStartup options.AddJob(Triggers.Period(10000)); options.AddJob(Triggers.Cron("0 0 0,12 ? * ?",CronStringFormat.WithSeconds)); // 表示每天凌晨与12点 }); - services.AddFileLogging("application-{0:yyyy}-{0:MM}-{0:dd}.log", options => + services.AddFileLogging("log/application-{0:yyyy}-{0:MM}-{0:dd}.log", options => { options.Append = true; options.MinimumLevel = LogLevel.Information;