Files
ThingsGateway/src/Admin/ThingsGateway.Admin.Application/Services/User/SysUserService.cs
2025-06-11 10:26:48 +08:00

924 lines
39 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
//------------------------------------------------------------------------------
using BootstrapBlazor.Components;
using Mapster;
using ThingsGateway.DataEncryption;
using ThingsGateway.Extension;
using ThingsGateway.Extension.Generic;
using ThingsGateway.FriendlyException;
using ThingsGateway.NewLife.Json.Extension;
using ThingsGateway.SqlSugar;
namespace ThingsGateway.Admin.Application;
internal sealed class SysUserService : BaseService<SysUser>, ISysUserService
{
private readonly IRelationService _relationService;
private readonly ISysResourceService _sysResourceService;
private readonly ISysRoleService _roleService;
private readonly ISysDictService _configService;
private readonly ISysPositionService _sysPositionService;
private readonly ISysOrgService _sysOrgService;
private readonly IVerificatInfoService _verificatInfoService;
public SysUserService(
IVerificatInfoService verificatInfoService,
IRelationService relationService,
ISysPositionService sysPositionService,
ISysOrgService sysOrgService,
ISysResourceService sysResourceService,
ISysRoleService roleService,
ISysDictService configService)
{
_sysOrgService = sysOrgService;
_sysPositionService = sysPositionService;
_relationService = relationService;
_sysResourceService = sysResourceService;
_roleService = roleService;
_configService = configService;
_verificatInfoService = verificatInfoService;
}
#region
/// <inheritdoc/>
public async Task<HashSet<long>?> GetCurrentUserDataScopeAsync()
{
if (UserManager.SuperAdmin || UserManager.UserId == 0)
return null;
var userInfo = await GetUserByIdAsync(UserManager.UserId).ConfigureAwait(false);//获取用户信息
var roles = await _roleService.GetRoleListByUserIdAsync(UserManager.UserId).ConfigureAwait(false);
if (roles.Any(a => a.DefaultDataScope.ScopeCategory == DataScopeEnum.SCOPE_ALL))
{
return null;
}
else
{
var scopeDefineOrgIdList = roles.Where(a => a.DefaultDataScope.ScopeCategory == DataScopeEnum.SCOPE_ORG_DEFINE).SelectMany(a => a.DefaultDataScope.ScopeDefineOrgIdList);
HashSet<long> orgChilds = new();
HashSet<long> orgs = new();
if (roles.Any(a => a.DefaultDataScope.ScopeCategory == DataScopeEnum.SCOPE_ORG_CHILD))
{
orgChilds = userInfo.ScopeOrgChildList;
}
if (roles.Any(a => a.DefaultDataScope.ScopeCategory == DataScopeEnum.SCOPE_ORG_CHILD))
{
orgs = new HashSet<long>() { userInfo.OrgId };
}
return scopeDefineOrgIdList.Concat(orgChilds).Concat(orgs).ToHashSet();
}
}
/// <inheritdoc/>
public async Task<bool> CheckApiDataScopeAsync(long? orgId, long createUerId, bool throwEnable = true)
{
var hasPermission = true;
//判断数据范围
var dataScope = await GetCurrentUserDataScopeAsync().ConfigureAwait(false);
if (dataScope is { Count: > 0 })//如果有机构
{
if (orgId == null || !dataScope.Contains(orgId.Value))//判断机构id是否在数据范围
hasPermission = false;
}
else if (dataScope is { Count: 0 })// 表示仅自己
{
if (createUerId != 0 && createUerId != UserManager.UserId)
hasPermission = false;//机构的创建人不是自己则报错
}
if (!hasPermission && throwEnable)
{
throw Oops.Bah(App.CreateLocalizerByType(typeof(ThingsGateway.Admin.Application.OperDescAttribute))["NoPermission"]);
}
return hasPermission;
}
public async Task<bool> CheckApiDataScopeAsync(IEnumerable<long> orgIds, IEnumerable<long> createUerIds, bool throwEnable = true)
{
var hasPermission = true;
//判断数据范围
var dataScope = await GetCurrentUserDataScopeAsync().ConfigureAwait(false);
if (dataScope is { Count: > 0 })//如果有机构
{
if (orgIds == null || !dataScope.ContainsAll(orgIds))//判断机构id列表是否全在数据范围
hasPermission = false;
}
else if (dataScope is { Count: 0 })// 表示仅自己
{
if (createUerIds.Any(it => it != 0 && it != UserManager.UserId))//如果创建者id里有任何不是自己创建的机构
hasPermission = false;
}
if (!hasPermission && throwEnable)
{
throw Oops.Bah(App.CreateLocalizerByType(typeof(ThingsGateway.Admin.Application.OperDescAttribute))["NoPermission"]);
}
return hasPermission;
}
#endregion
#region
/// <inheritdoc/>
public async Task<SysUser?> GetUserByAccountAsync(string account, long? tenantId)
{
var userId = await GetIdByAccountAsync(account, tenantId).ConfigureAwait(false);//获取用户ID
if (userId > 0)
{
var sysUser = await GetUserByIdAsync(userId).ConfigureAwait(false);//获取用户信息
if (sysUser?.Account == account)
return sysUser;
else
return null;
}
else
{
return null;
}
}
/// <summary>
/// 根据用户id获取用户不存在返回null
/// </summary>
/// <param name="userId">用户id</param>
/// <returns>用户</returns>
public async Task<SysUser?> GetUserByIdAsync(long userId)
{
//先从Cache拿
var sysUser = App.CacheService.HashGetOne<SysUser>(CacheConst.Cache_SysUser, userId.ToString());
sysUser ??= await GetUserFromDbAsync(userId).ConfigureAwait(false);//从数据库拿用户信息
return sysUser;
}
/// <summary>
/// 根据账号获取用户id
/// </summary>
/// <param name="account">账号</param>
/// <param name="tenantId">租户id</param>
/// <returns>用户id</returns>
public async Task<long> GetIdByAccountAsync(string account, long? tenantId)
{
var key = CacheConst.Cache_SysUserAccount;
var orgIds = new HashSet<long>();
if (tenantId > 0)
{
key += $":{tenantId}";
orgIds = await _sysOrgService.GetOrgChildIdsAsync(tenantId.Value).ConfigureAwait(false);//获取下级机构
}
//先从Cache拿
var userId = App.CacheService.HashGetOne<long>(key, account);
if (userId == 0)
{
//单查获取用户账号对应ID
using var db = GetDB();
userId = await db.Queryable<SysUser>()
.Where(it => it.Account == account)
.WhereIF(orgIds.Count > 0, it => orgIds.Contains(it.OrgId))
.Select(it => it.Id).FirstAsync().ConfigureAwait(false);
if (userId != 0)
{
//插入Cache
App.CacheService.HashAdd(key, account, userId);
}
}
return userId;
}
/// <summary>
/// 获取用户拥有的按钮编码
/// </summary>
/// <param name="userId">用户id</param>
/// <returns>按钮编码</returns>
public async Task<Dictionary<string, List<string>>> GetButtonCodeListAsync(long userId)
{
//获取用户资源集合
var resourceList = await _relationService.GetRelationListByObjectIdAndCategoryAsync(userId, RelationCategoryEnum.UserHasResource).ConfigureAwait(false);
if (!resourceList.Any())//如果有表示用户单独授权了不走用户角色
{
//获取用户角色关系集合
var roleList = await _relationService.GetRelationListByObjectIdAndCategoryAsync(userId, RelationCategoryEnum.UserHasRole).ConfigureAwait(false);
var roleIdList = roleList.Select(x => x.TargetId.ToLong());//角色ID列表
if (roleIdList.Any())//如果该用户有角色
{
resourceList = await _relationService.GetRelationListByObjectIdListAndCategoryAsync(roleIdList,
RelationCategoryEnum.RoleHasResource).ConfigureAwait(false);//获取资源集合
}
}
var relationResourcePermissions = resourceList.Select(it => it.ExtJson?.FromJsonNetString<RelationResourcePermission>());
var allResources = await _sysResourceService.GetAllAsync().ConfigureAwait(false);
var ids = relationResourcePermissions.Select(a => a.MenuId);
var menus = allResources.Where(it => it.Category == ResourceCategoryEnum.Menu && ids.Contains(it.Id)).ToDictionary(a => a, a => relationResourcePermissions.FirstOrDefault(b => b.MenuId == a.Id));
Dictionary<string, List<string>> buttonCodeList = new();
foreach (var item in menus)
{
if (buttonCodeList.TryGetValue(item.Key.Href, out var buttonCode))
{
var buttonS = allResources.Where(a => item.Value.ButtonIds.Contains(a.Id));
buttonCode.AddRange(buttonS.Select(a => a.Title));
}
else
{
var buttonS = allResources.Where(a => item.Value.ButtonIds.Contains(a.Id));
buttonCodeList.Add(item.Key.Href, buttonS.Select(a => a.Title).ToList());
}
}
var firstbuttons = allResources.Where(it => it.Category == ResourceCategoryEnum.Button && relationResourcePermissions.FirstOrDefault(a => a.MenuId == 0)?.ButtonIds?.Contains(it.Id) == true);
buttonCodeList.Add(string.Empty, firstbuttons?.Select(a => a.Title).ToList());
return buttonCodeList!;
}
/// <inheritdoc/>
public async Task<IEnumerable<DataScope>> GetPermissionListByUserIdAsync(long userId)
{
List<DataScope>? permissions = new();
#region Razor页面权限
{
var sysRelations =
await _relationService.GetRelationListByObjectIdAndCategoryAsync(userId, RelationCategoryEnum.UserHasPermission).ConfigureAwait(false);//根据用户ID获取用户权限
if (!sysRelations.Any())//如果有表示用户单独授权了不走用户角色
{
var roleIdList =
await _relationService.GetRelationListByObjectIdAndCategoryAsync(userId, RelationCategoryEnum.UserHasRole).ConfigureAwait(false);//根据用户ID获取角色ID
if (roleIdList.Any())//如果角色ID不为空
{
//获取角色权限信息
sysRelations = await _relationService.GetRelationListByObjectIdListAndCategoryAsync(roleIdList.Select(it => it.TargetId.ToLong()),
RelationCategoryEnum.RoleHasPermission).ConfigureAwait(false);
}
}
var relationGroup = sysRelations.GroupBy(it => it.TargetId);//根据目标ID,也就是接口名分组,因为存在一个用户多个角色
//遍历分组
foreach (var it in relationGroup)
{
permissions.Add(new DataScope
{
ApiUrl = it.Key,
});
}
}
#endregion Razor页面权限
#region API权限
{
var apiRelations =
await _relationService.GetRelationListByObjectIdAndCategoryAsync(userId, RelationCategoryEnum.UserHasOpenApiPermission).ConfigureAwait(false);//根据用户ID获取用户权限
if (!apiRelations.Any())//如果有表示用户单独授权了不走用户角色
{
var roleIdList =
await _relationService.GetRelationListByObjectIdAndCategoryAsync(userId, RelationCategoryEnum.UserHasRole).ConfigureAwait(false);//根据用户ID获取角色ID
if (roleIdList.Any())//如果角色ID不为空
{
//获取角色权限信息
apiRelations = await _relationService.GetRelationListByObjectIdListAndCategoryAsync(roleIdList.Select(it => it.TargetId.ToLong()),
RelationCategoryEnum.RoleHasOpenApiPermission).ConfigureAwait(false);
}
}
var relationGroup = apiRelations.GroupBy(it => it.TargetId);//根据目标ID,也就是接口名分组,因为存在一个用户多个角色
//遍历分组
foreach (var it in relationGroup)
{
permissions.Add(new DataScope
{
ApiUrl = it.Key,
});
}
}
#endregion API权限
return permissions;
}
/// <summary>
/// 表格查询
/// </summary>
/// <param name="option">查询条件</param>
/// <param name="input">查询条件</param>
public async Task<QueryData<SysUser>> PageAsync(QueryPageOptions option, UserSelectorInput input)
{
if (input != null)
{
option.SortName = "u." + option.SortName;
var orgIds = await _sysOrgService.GetOrgChildIdsAsync(input.OrgId).ConfigureAwait(false);//获取下级机构
var dataScope = await GetCurrentUserDataScopeAsync().ConfigureAwait(false);
return await QueryAsync(option, query =>
query.WhereIF(!option.SearchText.IsNullOrWhiteSpace(), a => a.Account.Contains(option.SearchText))
.WhereIF(input.OrgId > 0, u => orgIds.Contains(u.OrgId))//指定机构
.WhereIF(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.OrgId))//在指定机构列表查询
.WhereIF(dataScope?.Count == 0, u => u.CreateUserId == UserManager.UserId)
.WhereIF(input.PositionId > 0, u => u.PositionId == input.PositionId)//指定职位
.WhereIF(input.RoleId > 0,
u => SqlFunc.Subqueryable<SysRelation>()
.Where(r => r.TargetId == input.RoleId.ToString() && r.ObjectId == u.Id && r.Category == RelationCategoryEnum.UserHasRole)
.Any())//指定角色
.LeftJoin<SysOrg>((u, o) => u.OrgId == o.Id).LeftJoin<SysPosition>((u, o, p) => u.PositionId == p.Id)
.Select((u, o, p) => new SysUser
{
Id = u.Id.SelectAll(),
OrgName = o.Name,
PositionName = p.Name,
OrgNames = o.Names
}
)
.Mapper(u =>
{
#pragma warning disable CS8625 // 无法将 null 字面量转换为非 null 的引用类型。
u.Password = null;//密码清空
u.Phone = DESEncryption.Decrypt(u.Phone);//解密手机号
#pragma warning restore CS8625 // 无法将 null 字面量转换为非 null 的引用类型。
})).ConfigureAwait(false);
}
else
{
return await QueryAsync(option, query =>
query.WhereIF(!option.SearchText.IsNullOrWhiteSpace(), a => a.Account.Contains(option.SearchText)).Mapper(u =>
{
#pragma warning disable CS8625 // 无法将 null 字面量转换为非 null 的引用类型。
u.Password = null;//密码清空
u.Phone = DESEncryption.Decrypt(u.Phone);//解密手机号
#pragma warning restore CS8625 // 无法将 null 字面量转换为非 null 的引用类型。
})).ConfigureAwait(false);
}
}
/// <summary>
/// 获取用户拥有的角色
/// </summary>
/// <param name="id">用户id</param>
/// <returns>角色id列表</returns>
public async Task<IEnumerable<long>> OwnRoleAsync(long id)
{
var relations = await _relationService.GetRelationListByObjectIdAndCategoryAsync(id, RelationCategoryEnum.UserHasRole).ConfigureAwait(false);
return relations.Select(it => it.TargetId.ToLong());
}
/// <summary>
/// 获取用户拥有的资源
/// </summary>
/// <param name="id">用户id</param>
public async Task<GrantResourceData> OwnResourceAsync(long id)
{
return await _roleService.OwnResourceAsync(id, RelationCategoryEnum.UserHasResource).ConfigureAwait(false);
}
/// <summary>
/// 根据用户id获取用户列表
/// </summary>
/// <param name="input">用户id列表</param>
/// <returns>用户列表</returns>
public async Task<List<UserSelectorOutput>> GetUserListByIdListAsync(IEnumerable<long> input)
{
using var db = GetDB();
var userList = await db.Queryable<SysUser>().Where(it => input.Contains(it.Id)).Select<UserSelectorOutput>().ToListAsync().ConfigureAwait(false);
return userList;
}
#endregion
#region OPENAPI
/// <summary>
/// 获取用户拥有的OpenApi权限
/// </summary>
/// <param name="id">用户id</param>
public async Task<GrantPermissionData> ApiOwnPermissionAsync(long id)
{
var roleOwnPermission = new GrantPermissionData { Id = id };//定义结果集
//获取关系列表
var relations = await _relationService.GetRelationListByObjectIdAndCategoryAsync(id, RelationCategoryEnum.UserHasOpenApiPermission).ConfigureAwait(false);
roleOwnPermission.GrantInfoList = relations.Select(it => it.ExtJson?.FromJsonNetString<RelationPermission>()!).Where(a => a != null);
return roleOwnPermission;
}
/// <inheritdoc />
[OperDesc("UserGrantApiPermission")]
public async Task GrantApiPermissionAsync(GrantPermissionData input)
{
var sysUser = await GetUserByIdAsync(input.Id).ConfigureAwait(false);//获取用户
await CheckApiDataScopeAsync(sysUser.OrgId, sysUser.CreateUserId).ConfigureAwait(false);
if (sysUser != null)
{
await _relationService.SaveRelationBatchAsync(RelationCategoryEnum.UserHasOpenApiPermission, input.Id,
input.GrantInfoList.Select(a => (a.ApiUrl, a.ToSystemTextJsonString())),
true).ConfigureAwait(false);//添加到数据库
DeleteUserFromCache(input.Id);
}
}
#endregion OPENAPI
#region
/// <inheritdoc/>
[OperDesc("SaveUser", isRecordPar: false)]
public async Task<bool> SaveUserAsync(SysUser input, ItemChangedType changedType)
{
await CheckInput(input).ConfigureAwait(false);//检查参数
if (changedType == ItemChangedType.Add)
{
var sysUser = input.Adapt<SysUser>();
//获取默认密码
sysUser.Avatar = input.Avatar;
sysUser.Password = await GetDefaultPassWord(true).ConfigureAwait(false);//设置密码
sysUser.Status = true;//默认状态
return await SaveAsync(sysUser, changedType).ConfigureAwait(false);//添加数据
}
else
{
await CheckApiDataScopeAsync(input.OrgId, input.CreateUserId).ConfigureAwait(false);
var exist = await GetUserByIdAsync(input.Id).ConfigureAwait(false);//获取用户信息
if (exist != null)
{
var isSuperAdmin = exist.Id == RoleConst.SuperAdminId;//判断是否有超管
if (isSuperAdmin && !UserManager.SuperAdmin)
throw Oops.Bah(Localizer["CanotEditAdminUser"]);
if (input.Status != exist.Status)
CheckSelf(input.Id, input.Status ? Localizer["Enable"] : Localizer["Disable"]);//判断是不是自己
var sysUser = input;//实体转换
using var db = GetDB();
var result = await db.Updateable(sysUser).IgnoreColumns(it =>
new
{
//忽略更新字段
it.Password,
it.LastLoginDevice,
it.LastLoginIp,
it.LastLoginTime,
it.LatestLoginDevice,
it.LatestLoginIp,
it.LatestLoginTime
}).ExecuteCommandAsync().ConfigureAwait(false) > 0;
if (result)//修改数据
{
DeleteUserFromCache(sysUser.Id);//删除用户缓存
var verificatInfoIds = _verificatInfoService.GetListByUserId(sysUser.Id);
//从列表中删除
//删除用户verificat缓存
_verificatInfoService.Delete(verificatInfoIds.Select(a => a.Id).ToList());
await NoticeUtil.UserLoginOut(new UserLoginOutEvent() { ClientIds = verificatInfoIds.SelectMany(a => a.ClientIds).ToList(), Message = Localizer["ExitVerificat"] }).ConfigureAwait(false);
}
return result;
}
}
return false;
}
#endregion
#region
/// <inheritdoc/>
[OperDesc("ResetPassword")]
public async Task ResetPasswordAsync(long id)
{
var sysUser = await GetUserByIdAsync(id).ConfigureAwait(false);
await CheckApiDataScopeAsync(sysUser.OrgId, sysUser.CreateUserId).ConfigureAwait(false);
var password = await GetDefaultPassWord(true).ConfigureAwait(false);//获取默认密码,这里不走Aop所以需要加密一下
using var db = GetDB();
//重置密码
if (await db.UpdateSetColumnsTrueAsync<SysUser>(it => new SysUser
{
Password = password
}, it => it.Id == id).ConfigureAwait(false))
{
DeleteUserFromCache(id);//从cache删除用户信息
var verificatInfoIds = _verificatInfoService.GetListByUserId(id);
//删除用户verificat缓存
_verificatInfoService.Delete(verificatInfoIds.Select(a => a.Id).ToList());
await NoticeUtil.UserLoginOut(new UserLoginOutEvent() { ClientIds = verificatInfoIds.SelectMany(a => a.ClientIds).ToList(), Message = Localizer["ExitVerificat"] }).ConfigureAwait(false);
}
}
/// <inheritdoc />
[OperDesc("UserGrantRole")]
public async Task GrantRoleAsync(GrantUserOrRoleInput input)
{
var sysUser = await GetUserByIdAsync(input.Id).ConfigureAwait(false);//获取用户信息
await CheckApiDataScopeAsync(sysUser.OrgId, sysUser.CreateUserId).ConfigureAwait(false);
if (sysUser != null)
{
var isSuperAdmin = (sysUser.Id == RoleConst.SuperAdminId || input.GrantInfoList.Any(a => a == RoleConst.SuperAdminRoleId)) && !UserManager.SuperAdmin;//判断是否有超管
if (isSuperAdmin)
throw Oops.Bah(Localizer["CanotGrantAdmin"]);
CheckSelf(input.Id, Localizer["GrantRole"]);//判断是不是自己
//给用户赋角色
await _relationService.SaveRelationBatchAsync(RelationCategoryEnum.UserHasRole, input.Id, input.GrantInfoList.Select(it => (it.ToString(), string.Empty)), true).ConfigureAwait(false);
DeleteUserFromCache(input.Id);//从cache删除用户信息
}
}
/// <inheritdoc />
[OperDesc("UserGrantResource")]
public async Task GrantResourceAsync(GrantResourceData input)
{
var menuIds = input.GrantInfoList.Select(it => it.MenuId).ToList();//菜单ID
var extJsons = input.GrantInfoList.Select(it => it.ToSystemTextJsonString()).ToList();//拓展信息
var relationUsers = new List<SysRelation>();//要添加的用户资源和授权关系表
var sysUser = await GetUserByIdAsync(input.Id).ConfigureAwait(false);//获取用户
await CheckApiDataScopeAsync(sysUser.OrgId, sysUser.CreateUserId).ConfigureAwait(false);
if (sysUser != null)
{
var resources = await _sysResourceService.GetAllAsync().ConfigureAwait(false);
var menusList = resources.Where(a => a.Category == ResourceCategoryEnum.Menu).Where(a => menuIds.Contains(a.Id));
#region
//获取我的模块信息Id列表
var moduleIds = menusList.Select(it => it.Module).Distinct();
foreach (var item in moduleIds)
{
//将角色资源添加到列表
relationUsers.Add(new SysRelation
{
ObjectId = sysUser.Id,
TargetId = item.ToString(),
Category = RelationCategoryEnum.UserHasModule
});
}
#endregion
#region
for (var i = 0; i < menuIds.Count; i++)
{
//将角色资源添加到列表
relationUsers.Add(new SysRelation
{
ObjectId = sysUser.Id,
TargetId = menuIds[i].ToString(),
Category = RelationCategoryEnum.UserHasResource,
ExtJson = extJsons?[i]
});
}
#endregion
#region .
//获取菜单信息
if (menusList.Any())
{
//获取权限授权树
var permissions = App.GetService<IApiPermissionService>().PermissionTreeSelector(menusList.Select(it => it.Href));
//要添加的角色有哪些权限列表
var relationUserPer = permissions.Select(it => new SysRelation
{
ObjectId = sysUser.Id,
TargetId = it.ApiRoute,
Category = RelationCategoryEnum.UserHasPermission,
ExtJson = new RelationPermission { ApiUrl = it.ApiRoute }
.ToSystemTextJsonString()
});
relationUsers.AddRange(relationUserPer);//合并列表
}
#endregion .
#region
using var db = GetDB();
//事务
var result = await db.UseTranAsync(async () =>
{
await db.Deleteable<SysRelation>(it =>
it.ObjectId == sysUser.Id && (it.Category == RelationCategoryEnum.UserHasPermission
|| it.Category == RelationCategoryEnum.UserHasResource
|| it.Category == RelationCategoryEnum.UserHasModule
)).ExecuteCommandAsync().ConfigureAwait(false);
await db.Insertable(relationUsers).ExecuteCommandAsync().ConfigureAwait(false);//添加新的
}).ConfigureAwait(false);
if (result.IsSuccess)//如果成功了
{
_relationService.RefreshCache(RelationCategoryEnum.UserHasPermission);//刷新关系缓存
_relationService.RefreshCache(RelationCategoryEnum.UserHasResource);//刷新关系缓存
_relationService.RefreshCache(RelationCategoryEnum.UserHasModule);//刷新关系缓存
DeleteUserFromCache(input.Id);//删除该用户缓存
}
else
{
throw new(result.ErrorMessage, result.ErrorException);
}
#endregion
}
}
#endregion
#region
/// <inheritdoc/>
[OperDesc("DeleteUser")]
public async Task<bool> DeleteUserAsync(IEnumerable<long> ids)
{
using var db = GetDB();
var containsSuperAdmin = await db.Queryable<SysUser>().Where(it => it.Id == RoleConst.SuperAdminId && ids.Contains(it.Id)).AnyAsync().ConfigureAwait(false);//判断是否有超管
if (containsSuperAdmin)
throw Oops.Bah(Localizer["CanotDeleteAdminUser"]);
if (ids.Contains(UserManager.UserId))
throw Oops.Bah(Localizer["CanotDeleteSelf"]);
var sysUsers = await GetUserListByIdListAsync(ids).ConfigureAwait(false);//获取用户信息
await CheckApiDataScopeAsync(sysUsers.Select(a => a.OrgId).ToList(), sysUsers.Select(a => a.CreateUserId).ToList()).ConfigureAwait(false);
//定义删除的关系
var delRelations = new List<RelationCategoryEnum>
{
RelationCategoryEnum.UserHasResource, RelationCategoryEnum.UserHasPermission, RelationCategoryEnum.UserHasRole, RelationCategoryEnum.UserHasOpenApiPermission
, RelationCategoryEnum.UserHasModule
};
//事务
var result = await db.UseTranAsync(async () =>
{
//清除该用户作为主管信息
await db.Updateable<SysUser>().SetColumns(it => new SysUser
{
DirectorId = null
})
.Where(it => ids.Contains(it.DirectorId.Value))
.ExecuteCommandAsync().ConfigureAwait(false);
//删除用户
await db.Deleteable<SysUser>().In(ids.ToList()).ExecuteCommandHasChangeAsync().ConfigureAwait(false);//删除
//删除关系表用户与资源关系,用户与权限关系,用户与角色关系
await db.Deleteable<SysRelation>(it => ids.Contains(it.ObjectId) && delRelations.Contains(it.Category)).ExecuteCommandAsync().ConfigureAwait(false);
//删除组织表主管信息
await db.Deleteable<SysOrg>(it => ids.Contains(it.DirectorId.Value)).ExecuteCommandAsync().ConfigureAwait(false);
}).ConfigureAwait(false);
if (result.IsSuccess)//如果成功了
{
DeleteUserFromCache(ids);//cache删除用户
_relationService.RefreshCache(RelationCategoryEnum.UserHasRole);//关系表刷新UserHasRole缓存
_relationService.RefreshCache(RelationCategoryEnum.UserHasResource);//关系表刷新UserHasRole缓存
_relationService.RefreshCache(RelationCategoryEnum.UserHasModule);//关系表刷新UserHasModule缓存
_relationService.RefreshCache(RelationCategoryEnum.UserHasPermission);//关系表刷新UserHasRole缓存
_relationService.RefreshCache(RelationCategoryEnum.UserHasOpenApiPermission);//关系表刷新Relation_SYS_USER_HAS_OPENAPIPERMISSION缓存
//将这些用户踢下线,并永久注销这些用户
foreach (var id in ids)
{
var verificatInfoIds = _verificatInfoService.GetListByUserId(id);
_verificatInfoService.Delete(verificatInfoIds.Select(a => a.Id).ToList());
await UserLoginOut(id, verificatInfoIds.SelectMany(a => a.ClientIds).ToList()).ConfigureAwait(false);
}
return true;
}
else
{
throw new(result.ErrorMessage, result.ErrorException);
}
}
/// <inheritdoc />
public void DeleteUserFromCache(long userId)
{
DeleteUserFromCache(new List<long>
{
userId
});
}
/// <inheritdoc />
public void DeleteUserFromCache(IEnumerable<long> ids)
{
var userIds = ids.Select(it => it.ToString()).ToArray();//id转string列表
var sysUsers = App.CacheService.HashGet<SysUser>(CacheConst.Cache_SysUser, userIds).Where(it => it != null);//获取用户列表
if (sysUsers.Any() == true)
{
var accounts = sysUsers.Where(it => it != null).Select(it => it.Account).ToArray();//账号集合
var phones = sysUsers.Select(it => it.Phone);//手机号集合
if (sysUsers.Any(it => it.TenantId != null))//如果有租户id不是空的表示是多租户模式
{
var userAccountKey = CacheConst.Cache_SysUserAccount;
var tenantIds = sysUsers.Where(it => it.TenantId != null).Select(it => it.TenantId.Value).Distinct().ToArray();//租户id列表
foreach (var tenantId in tenantIds)
{
userAccountKey = $"{userAccountKey}:{tenantId}";
//删除账号
App.CacheService.HashDel<long>(userAccountKey, accounts);
}
}
//删除用户信息
App.CacheService.HashDel<SysUser>(CacheConst.Cache_SysUser, userIds);
//删除账号
App.CacheService.HashDel<long>(CacheConst.Cache_SysUserAccount, accounts);
App.CacheService.HashDel<VerificatInfo>(CacheConst.Cache_Token, userIds.Select(it => it.ToString()).ToArray());
}
}
#endregion
#region
/// <summary>
/// 通知用户下线
/// </summary>
/// <param name="userId">用户ID</param>
/// <param name="verificatInfoIds">Token列表</param>
private async Task UserLoginOut(long userId, List<string>? verificatInfoIds)
{
await NoticeUtil.UserLoginOut(new UserLoginOutEvent
{
Message = Localizer["ExitVerificat"],
ClientIds = verificatInfoIds,
}).ConfigureAwait(false);//通知用户下线
}
/// <summary>
/// 获取默认密码
/// </summary>
/// <returns></returns>
private async Task<string> GetDefaultPassWord(bool isEncrypt = false)
{
//获取默认密码
var appConfig = await _configService.GetAppConfigAsync().ConfigureAwait(false);
return isEncrypt ? DESEncryption.Encrypt(appConfig.PasswordPolicy.DefaultPassword) : appConfig.PasswordPolicy.DefaultPassword;//判断是否需要加密
}
/// <summary>
/// 检查输入参数
/// </summary>
/// <param name="sysUser"></param>
private async Task CheckInput(SysUser sysUser)
{
var sysOrgList = await _sysOrgService.GetAllAsync().ConfigureAwait(false);//获取组织列表
var userOrg = sysOrgList.FirstOrDefault(it => it.Id == sysUser.OrgId);
if (userOrg == null)
throw Oops.Bah(Localizer[$"NoOrg"]);
var tenantId = await _sysOrgService.GetTenantIdByOrgIdAsync(sysUser.OrgId, sysOrgList).ConfigureAwait(false);
//判断账号重复,直接从cache拿
var accountId = await GetIdByAccountAsync(sysUser.Account, tenantId).ConfigureAwait(false);
if (accountId > 0 && accountId != sysUser.Id)
throw Oops.Bah(Localizer["AccountDup", sysUser.Account]);
//如果邮箱不是空
if (!string.IsNullOrEmpty(sysUser.Email))
{
var isMatch = sysUser.Email.MatchEmail();//验证邮箱格式
if (!isMatch)
throw Oops.Bah(Localizer["EmailError", sysUser.Email]);
using var db = GetDB();
if (await db.Queryable<SysUser>().Where(it => it.Email == sysUser.Email && it.Id != sysUser.Id).AnyAsync().ConfigureAwait(false))
throw Oops.Bah(Localizer["EmailDup", sysUser.Email]);
}
//如果手机号不是空
if (!string.IsNullOrEmpty(sysUser.Phone))
{
if (!sysUser.Phone.MatchPhoneNumber())//验证手机格式
throw Oops.Bah(Localizer["PhoneError", sysUser.Phone]);
sysUser.Phone = DESEncryption.Encrypt(sysUser.Phone);
}
if (sysUser.DirectorId == UserManager.UserId)
throw Oops.Bah(Localizer["DirectorSelf"]);
}
/// <summary>
/// 检查是否为自己
/// </summary>
/// <param name="id"></param>
/// <param name="operate">操作名称</param>
private void CheckSelf(long id, string operate)
{
if (id == UserManager.UserId)//如果是自己
{
throw Oops.Bah(Localizer["CheckSelf", operate]);
}
}
/// <summary>
/// 数据库获取用户信息
/// </summary>
/// <param name="userId">用户ID</param>
/// <returns></returns>
private async Task<SysUser?> GetUserFromDbAsync(long userId)
{
using var db = GetDB();
var sysUser = await db.Queryable<SysUser>()
.LeftJoin<SysOrg>((u, o) => u.OrgId == o.Id)//连表
.LeftJoin<SysPosition>((u, o, p) => u.PositionId == p.Id)//连表
.Where(u => u.Id == userId)
.Select((u, o, p) => new SysUser
{
Id = u.Id.SelectAll(),
OrgName = o.Name,
OrgNames = o.Names,
PositionName = p.Name,
OrgAndPosIdList = o.ParentIdList
}).FirstAsync()
.ConfigureAwait(false);
if (sysUser != null)
{
sysUser.Password = DESEncryption.Decrypt(sysUser.Password);//解密密码
sysUser.Phone = DESEncryption.Decrypt(sysUser.Phone);//解密手机号
sysUser.OrgAndPosIdList.AddRange(sysUser.OrgId, sysUser.PositionId ?? 0);//添加组织和职位Id
if (sysUser.DirectorId != null)
{
sysUser.DirectorInfo = (await GetUserByIdAsync(sysUser.DirectorId.Value).ConfigureAwait(false)).Adapt<UserSelectorOutput>();//获取主管信息
}
//获取按钮码
var buttonCodeList = await GetButtonCodeListAsync(sysUser.Id).ConfigureAwait(false);
//获取数据权限
var dataScopeList = await GetPermissionListByUserIdAsync(sysUser.Id).ConfigureAwait(false);
//获取权限码
var permissionCodeList = dataScopeList.Select(it => it.ApiUrl).ToHashSet();
//获取角色码
var roleCodeList = await _roleService.GetRoleListByUserIdAsync(sysUser.Id).ConfigureAwait(false);
//权限码赋值
sysUser.ButtonCodeList = buttonCodeList;
sysUser.RoleIdList = roleCodeList.Select(it => it.Id).ToHashSet();
sysUser.PermissionCodeList = permissionCodeList;
sysUser.IsGlobal = roleCodeList.Any(a => a.Category == RoleCategoryEnum.Global);
var sysOrgList = await _sysOrgService.GetAllAsync().ConfigureAwait(false);
var scopeOrgChildList =
(await _sysOrgService.GetChildListByIdAsync(sysUser.OrgId, true, sysOrgList).ConfigureAwait(false)).Select(it => it.Id).ToHashSet();//获取所属机构的下级机构Id列表
sysUser.ScopeOrgChildList = scopeOrgChildList;
var tenantId = await _sysOrgService.GetTenantIdByOrgIdAsync(sysUser.OrgId, sysOrgList).ConfigureAwait(false);
sysUser.TenantId = tenantId;
if (sysUser.Id == RoleConst.SuperAdminId)
{
var modules = (await _sysResourceService.GetAllAsync().ConfigureAwait(false)).Where(a => a.Category == ResourceCategoryEnum.Module).OrderBy(a => a.SortCode);
sysUser.ModuleList = modules.ToList();//模块列表赋值给用户
}
else
{
var moduleIds = await _relationService.GetUserModuleId(sysUser.RoleIdList, sysUser.Id).ConfigureAwait(false);//获取模块ID列表
var modules = (await _sysResourceService.GetMuduleByMuduleIdsAsync(moduleIds).ConfigureAwait(false)).OrderBy(a => a.SortCode);//获取模块列表
sysUser.ModuleList = modules.ToList();//模块列表赋值给用户
}
//插入Cache
App.CacheService.HashAdd(CacheConst.Cache_SysUserAccount, sysUser.Account, sysUser.Id);
App.CacheService.HashAdd(CacheConst.Cache_SysUser, sysUser.Id.ToString(), sysUser);
return sysUser;
}
return null;
}
#endregion
}