feat:完成后端数据权限过滤
This commit is contained in:
@@ -14,6 +14,8 @@ namespace Yi.Framework.Infrastructure.Const
|
|||||||
|
|
||||||
public const string TenantId = nameof(TenantId);
|
public const string TenantId = nameof(TenantId);
|
||||||
|
|
||||||
|
public const string DeptId= nameof(DeptId);
|
||||||
|
|
||||||
public const string Email = nameof(Email);
|
public const string Email = nameof(Email);
|
||||||
|
|
||||||
public const string PhoneNumber = nameof(PhoneNumber);
|
public const string PhoneNumber = nameof(PhoneNumber);
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ namespace Yi.Framework.Infrastructure.CurrentUsers
|
|||||||
|
|
||||||
public long Id => FindUserId();
|
public long Id => FindUserId();
|
||||||
|
|
||||||
|
public long DeptId => FindDeptId();
|
||||||
|
|
||||||
|
|
||||||
public string UserName => this.FindClaimValue(TokenTypeConst.UserName);
|
public string UserName => this.FindClaimValue(TokenTypeConst.UserName);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -59,7 +62,21 @@ namespace Yi.Framework.Infrastructure.CurrentUsers
|
|||||||
return FindClaim(claimType)?.Value;
|
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()
|
public long FindUserId()
|
||||||
{
|
{
|
||||||
var userIdOrNull = _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == TokenTypeConst.Id);
|
var userIdOrNull = _principalAccessor.Principal?.Claims?.FirstOrDefault(c => c.Type == TokenTypeConst.Id);
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ namespace Yi.Framework.Infrastructure.CurrentUsers
|
|||||||
public bool IsAuthenticated { get; }
|
public bool IsAuthenticated { get; }
|
||||||
public long Id { get; }
|
public long Id { get; }
|
||||||
|
|
||||||
|
public long DeptId { get; }
|
||||||
|
|
||||||
public string UserName { get; }
|
public string UserName { get; }
|
||||||
|
|
||||||
public Guid TenantId { get; }
|
public Guid TenantId { get; }
|
||||||
|
|||||||
@@ -76,6 +76,10 @@ namespace Yi.Furion.Application.Rbac.Domain
|
|||||||
var claims = new Dictionary<string, object>();
|
var claims = new Dictionary<string, object>();
|
||||||
claims.Add(TokenTypeConst.Id, dto.User.Id);
|
claims.Add(TokenTypeConst.Id, dto.User.Id);
|
||||||
claims.Add(TokenTypeConst.UserName, dto.User.UserName);
|
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)
|
if (dto.User.Email is not null)
|
||||||
{
|
{
|
||||||
claims.Add(TokenTypeConst.Email, dto.User.Email);
|
claims.Add(TokenTypeConst.Email, dto.User.Email);
|
||||||
|
|||||||
@@ -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
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,5 +9,6 @@ namespace Yi.Furion.Application.Rbac.Services
|
|||||||
public interface IDeptService : ICrudAppService<DeptGetOutputDto, DeptGetListOutputDto, long, DeptGetListInputVo, DeptCreateInputVo, DeptUpdateInputVo>
|
public interface IDeptService : ICrudAppService<DeptGetOutputDto, DeptGetListOutputDto, long, DeptGetListInputVo, DeptCreateInputVo, DeptUpdateInputVo>
|
||||||
{
|
{
|
||||||
Task<List<long>> GetChildListAsync(long deptId);
|
Task<List<long>> GetChildListAsync(long deptId);
|
||||||
|
Task<List<DeptGetListOutputDto>> GetListRoleIdAsync([FromRoute] long roleId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ using Yi.Furion.Sqlsugar.Core.Repositories;
|
|||||||
|
|
||||||
namespace Yi.Furion.Application.Rbac.Services.Impl
|
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<MenuEntity> menuRepository, SmsAliyunManager smsAliyunManager, IOptions<SmsAliyunOptions> smsAliyunManagerOptions, SecurityCodeHelper securityCode, IMemoryCache memoryCache, IEventPublisher eventPublisher, IHttpContextAccessor httpContextAccessor) =>
|
public AccountService(IUserRepository userRepository, ICurrentUser currentUser, AccountManager accountManager, IRepository<MenuEntity> menuRepository, SmsAliyunManager smsAliyunManager, IOptions<SmsAliyunOptions> smsAliyunManagerOptions, SecurityCodeHelper securityCode, IMemoryCache memoryCache, IEventPublisher eventPublisher, IHttpContextAccessor httpContextAccessor) =>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Yi.Framework.Infrastructure.Ddd.Dtos;
|
|||||||
using Yi.Framework.Infrastructure.Ddd.Services;
|
using Yi.Framework.Infrastructure.Ddd.Services;
|
||||||
using Yi.Furion.Core.Rbac.Dtos.Dept;
|
using Yi.Furion.Core.Rbac.Dtos.Dept;
|
||||||
using Yi.Furion.Core.Rbac.Entities;
|
using Yi.Furion.Core.Rbac.Entities;
|
||||||
|
using Yi.Furion.Sqlsugar.Core.Repositories;
|
||||||
|
|
||||||
namespace Yi.Furion.Application.Rbac.Services.Impl
|
namespace Yi.Furion.Application.Rbac.Services.Impl
|
||||||
{
|
{
|
||||||
@@ -12,11 +13,12 @@ namespace Yi.Furion.Application.Rbac.Services.Impl
|
|||||||
public class DeptService : CrudAppService<DeptEntity, DeptGetOutputDto, DeptGetListOutputDto, long, DeptGetListInputVo, DeptCreateInputVo, DeptUpdateInputVo>,
|
public class DeptService : CrudAppService<DeptEntity, DeptGetOutputDto, DeptGetListOutputDto, long, DeptGetListInputVo, DeptCreateInputVo, DeptUpdateInputVo>,
|
||||||
IDeptService, ITransient, IDynamicApiController
|
IDeptService, ITransient, IDynamicApiController
|
||||||
{
|
{
|
||||||
|
private IDeptRepository _deptRepository;
|
||||||
|
public DeptService(IDeptRepository deptRepository) { _deptRepository = deptRepository; }
|
||||||
[NonAction]
|
[NonAction]
|
||||||
public async Task<List<long>> GetChildListAsync(long deptId)
|
public async Task<List<long>> GetChildListAsync(long deptId)
|
||||||
{
|
{
|
||||||
var entities= await _DbQueryable.ToChildListAsync(x=>x.ParentId,deptId);
|
return await _deptRepository.GetChildListAsync(deptId);
|
||||||
return entities.Select(x => x.Id).ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -26,7 +28,7 @@ namespace Yi.Furion.Application.Rbac.Services.Impl
|
|||||||
//[Route("{roleId}")]
|
//[Route("{roleId}")]
|
||||||
public async Task<List<DeptGetListOutputDto>> GetListRoleIdAsync([FromRoute] long roleId)
|
public async Task<List<DeptGetListOutputDto>> GetListRoleIdAsync([FromRoute] long roleId)
|
||||||
{
|
{
|
||||||
var entities = await _DbQueryable.Where(d => SqlFunc.Subqueryable<RoleDeptEntity>().Where(rd => rd.RoleId == roleId && d.Id == rd.DeptId).Any()).ToListAsync();
|
var entities = await _deptRepository.GetListRoleIdAsync(roleId);
|
||||||
return await MapToGetListOutputDtosAsync(entities);
|
return await MapToGetListOutputDtosAsync(entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,14 +24,6 @@ namespace Yi.Furion.Application.Rbac.Services.Impl
|
|||||||
|
|
||||||
private IRepository<RoleDeptEntity> _roleDeptRepository;
|
private IRepository<RoleDeptEntity> _roleDeptRepository;
|
||||||
|
|
||||||
|
|
||||||
public async Task<List<long>> GetDeptIdsAsync(long roleId)
|
|
||||||
{
|
|
||||||
var entities = await _roleDeptRepository.GetListAsync(x => x.RoleId == roleId);
|
|
||||||
return entities.Select(x => x.DeptId).ToList();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[UnitOfWork]
|
[UnitOfWork]
|
||||||
public async Task UpdateDataScpoceAsync(UpdateDataScpoceInput input)
|
public async Task UpdateDataScpoceAsync(UpdateDataScpoceInput input)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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<List<long>> GetChildListAsync(long deptId);
|
||||||
|
Task<List<DeptEntity>> GetListRoleIdAsync([FromRoute] long roleId);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<DeptEntity>, IDeptRepository, ITransient
|
||||||
|
{
|
||||||
|
public DeptRepository(ISqlSugarClient context) : base(context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<long>> GetChildListAsync(long deptId)
|
||||||
|
{
|
||||||
|
var entities = await _DbQueryable.ToChildListAsync(x => x.ParentId, deptId);
|
||||||
|
return entities.Select(x => x.Id).ToList();
|
||||||
|
}
|
||||||
|
public async Task<List<DeptEntity>> GetListRoleIdAsync([FromRoute] long roleId)
|
||||||
|
{
|
||||||
|
|
||||||
|
return await _DbQueryable.Where(d => SqlFunc.Subqueryable<RoleDeptEntity>().Where(rd => rd.RoleId == roleId && d.Id == rd.DeptId).Any()).ToListAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Furion;
|
using Furion;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Newtonsoft.Json.Schema;
|
||||||
using Yi.Framework.Infrastructure.Sqlsugar;
|
using Yi.Framework.Infrastructure.Sqlsugar;
|
||||||
|
|
||||||
namespace Yi.Furion.Sqlsugar.Core;
|
namespace Yi.Furion.Sqlsugar.Core;
|
||||||
|
|||||||
@@ -1,13 +1,21 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Furion.LinqBuilder;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using SqlSugar;
|
using SqlSugar;
|
||||||
using Yi.Framework.Infrastructure.CurrentUsers;
|
using Yi.Framework.Infrastructure.CurrentUsers;
|
||||||
|
using Yi.Framework.Infrastructure.Data.Filters;
|
||||||
using Yi.Framework.Infrastructure.Sqlsugar;
|
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
|
namespace Yi.Furion.Sqlsugar.Core
|
||||||
{
|
{
|
||||||
@@ -23,12 +31,29 @@ namespace Yi.Furion.Sqlsugar.Core
|
|||||||
|
|
||||||
//进行Aop数据权限过滤
|
//进行Aop数据权限过滤
|
||||||
protected override void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient)
|
protected override void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient)
|
||||||
|
{
|
||||||
|
//由于此处数据过滤为最底层,不能依赖仓储
|
||||||
|
DataScopeFilter(sqlSugarClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据权限过滤
|
||||||
|
/// </summary>
|
||||||
|
private async void DataScopeFilter(ISqlSugarClient sqlSugarClient)
|
||||||
{
|
{
|
||||||
//这里Aop进行数据权限过滤
|
//这里Aop进行数据权限过滤
|
||||||
var userId = _currentUser.Id;
|
var userId = _currentUser.Id;
|
||||||
if (userId == 0) return;
|
var userName = _currentUser.UserName;
|
||||||
_logger.LogInformation($"用户【{userId}】访问Aop");
|
var deptId = _currentUser.DeptId;
|
||||||
|
//超管或者
|
||||||
|
if (userId == 0 || UserConst.Admin.Equals(userName)) return;
|
||||||
|
|
||||||
|
//如果没有部门,只能看到自己
|
||||||
|
if (deptId == 0)
|
||||||
|
{
|
||||||
|
sqlSugarClient.QueryFilter.AddTableFilter<UserEntity>(x => x.Id == userId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* 这里数据权限,步骤:
|
* 这里数据权限,步骤:
|
||||||
* 1:获取用户id
|
* 1:获取用户id
|
||||||
@@ -37,6 +62,50 @@ namespace Yi.Furion.Sqlsugar.Core
|
|||||||
* 4:会涉及部门表的筛选,所以还需要获取用户的所在部门,如果没有部门,那就是过滤到只看自己
|
* 4:会涉及部门表的筛选,所以还需要获取用户的所在部门,如果没有部门,那就是过滤到只看自己
|
||||||
* 5:可直接使用DB进行查询部门即可
|
* 5:可直接使用DB进行查询部门即可
|
||||||
*/
|
*/
|
||||||
|
var roles = await sqlSugarClient.Queryable<RoleEntity>().Where(x => SqlFunc.Subqueryable<UserRoleEntity>().Where(ur =>ur.UserId == userId).Any()).ToListAsync();
|
||||||
|
//获取到全部角色
|
||||||
|
|
||||||
|
Expression<Func<UserEntity, bool>> 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<DeptEntity>().Where(x => SqlFunc.Subqueryable<RoleDeptEntity>().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<DeptEntity>().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<UserEntity>(expression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class Startup : AppStartup
|
|||||||
options.AddJob<TestJob>(Triggers.Period(10000));
|
options.AddJob<TestJob>(Triggers.Period(10000));
|
||||||
options.AddJob<SystemDataJob>(Triggers.Cron("0 0 0,12 ? * ?",CronStringFormat.WithSeconds)); // 表示每天凌晨与12点
|
options.AddJob<SystemDataJob>(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.Append = true;
|
||||||
options.MinimumLevel = LogLevel.Information;
|
options.MinimumLevel = LogLevel.Information;
|
||||||
|
|||||||
Reference in New Issue
Block a user