UNIVPLMDataIntegration/Admin.NET/Admin.NET.Core/Service/Auth/SysAuthService.cs
2025-09-04 12:28:34 +08:00

651 lines
29 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.

// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Furion.SpecificationDocument;
using Lazy.Captcha.Core;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Controllers;
namespace Admin.NET.Core.Service;
/// <summary>
/// 系统登录授权服务 🧩
/// </summary>
[ApiDescriptionSettings(Order = 500, Description = "登录授权")]
[AppApiDescription("登录授权")]
public class SysAuthService : IDynamicApiController, ITransient
{
private readonly UserManager _userManager;
private readonly SqlSugarRepository<SysUser> _sysUserRep;
private readonly SysConfigService _sysConfigService;
private readonly SysCacheService _sysCacheService;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IApiDescriptionGroupCollectionProvider _apiProvider;
private readonly ICaptcha _captcha;
private readonly IEventPublisher _eventPublisher;
public SysAuthService(UserManager userManager,
SqlSugarRepository<SysUser> sysUserRep,
SysConfigService sysConfigService,
SysCacheService sysCacheService,
IApiDescriptionGroupCollectionProvider apiProvider,
IHttpContextAccessor httpContextAccessor,
ICaptcha captcha,
IEventPublisher eventPublisher)
{
_userManager = userManager;
_sysUserRep = sysUserRep;
_apiProvider = apiProvider;
_sysConfigService = sysConfigService;
_sysCacheService = sysCacheService;
_httpContextAccessor = httpContextAccessor;
_captcha = captcha;
_eventPublisher = eventPublisher;
}
/// <summary>
/// 账号密码登录 🔖
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[DisplayName("账号密码登录")]
[AllowAnonymous]
public virtual async Task<LoginOutput> Login([Required] LoginInput input)
{
// 判断密码错误次数缓存30分钟
var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{input.Account}";
var passwordErrorTimes = _sysCacheService.Get<int>(keyPasswordErrorTimes);
var passwordMaxErrorTimes = await _sysConfigService.GetConfigValueByCode<int>(ConfigConst.SysPasswordMaxErrorTimes);
// 若未配置或误配置为0、负数, 则默认密码错误次数最大为5次
if (passwordMaxErrorTimes < 1) passwordMaxErrorTimes = 5;
if (passwordErrorTimes > passwordMaxErrorTimes) throw Oops.Oh(ErrorCodeEnum.D1027);
// 判断是否开启验证码并校验
input.TenantId = input.TenantId <= 0 ? SqlSugarConst.DefaultTenantId : input.TenantId;
var tenant = _sysCacheService.Get<List<SysTenant>>(CacheConst.KeyTenant)?.FirstOrDefault(u => u.Id == input.TenantId);
if (tenant == null)
{
await App.GetRequiredService<SysTenantService>().CacheTenant(); // 重新生成租户列表缓存
tenant = _sysCacheService.Get<List<SysTenant>>(CacheConst.KeyTenant)?.FirstOrDefault(u => u.Id == input.TenantId);
if (tenant == null) throw Oops.Oh(ErrorCodeEnum.D0007);
}
if (tenant.Captcha == true && !_captcha.Validate(input.CodeId.ToString(), input.Code))
throw Oops.Oh(ErrorCodeEnum.D0008);
// 获取并验证账号
var user = await GetLoginUser(input.TenantId, account: input.Account);
// 是否开启域登录验证
if (await _sysConfigService.GetConfigValueByCode<bool>(ConfigConst.SysDomainLogin))
{
var userLdap = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysUserLdap>>().GetFirstAsync(u => u.UserId == user.Id && u.TenantId == user.TenantId);
if (userLdap == null)
{
VerifyPassword(input.Password, keyPasswordErrorTimes, passwordErrorTimes, user);
}
else if (!await App.GetRequiredService<SysLdapService>().AuthAccount(user.TenantId, userLdap.Account, CryptogramHelper.Decrypt(input.Password)))
{
_sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
throw Oops.Oh(ErrorCodeEnum.D1000);
}
}
else
VerifyPassword(input.Password, keyPasswordErrorTimes, passwordErrorTimes, user);
// 登录成功则清空密码错误次数
_sysCacheService.Remove(keyPasswordErrorTimes);
return await CreateToken(user);
}
/// <summary>
/// 获取登录用户
/// </summary>
/// <param name="tenantId"></param>
/// <param name="account"></param>
/// <param name="phone"></param>
/// <returns></returns>
[NonAction]
public async Task<SysUser> GetLoginUser(long tenantId, string account = null, string phone = null)
{
//// 若没有传值租户Id则从请求页URL参数中获取租户Id空则默认租户
//if (tenantId < 1)
//{
// var tenantidStr = _httpContextAccessor.HttpContext.Request.Query["tenantid"].ToString();
// tenantId = string.IsNullOrWhiteSpace(tenantidStr) ? SqlSugarConst.DefaultTenantId : long.Parse(tenantidStr);
//}
// 判断账号是否存在
var user = await _sysUserRep.AsQueryable().Includes(t => t.SysOrg).IgnoreTenant()
//.WhereIF(tenantId > 0, u => u.TenantId == tenantId)
.WhereIF(!string.IsNullOrWhiteSpace(account), u => u.Account.Equals(account))
.WhereIF(!string.IsNullOrWhiteSpace(phone), u => u.Phone.Equals(phone))
.FirstAsync();
_ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
// 判断账号是否被冻结
if (user.Status != StatusEnum.Enable) throw Oops.Oh(ErrorCodeEnum.D1017);
// 判断租户是否存在及状态
var tenant = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().GetFirstAsync(u => u.Id == user.TenantId);
if (tenant?.Status != StatusEnum.Enable) throw Oops.Oh(ErrorCodeEnum.Z1003);
return user;
}
/// <summary>
/// 验证用户密码
/// </summary>
/// <param name="password"></param>
/// <param name="keyPasswordErrorTimes"></param>
/// <param name="passwordErrorTimes"></param>
/// <param name="user"></param>
private void VerifyPassword(string password, string keyPasswordErrorTimes, int passwordErrorTimes, SysUser user)
{
// 国密SM2解密前端密码传输SM2加密后的
try
{
password = CryptogramHelper.SM2Decrypt(password);
}
catch
{
throw Oops.Oh(ErrorCodeEnum.D0010);
}
if (CryptogramHelper.CryptoType == CryptogramEnum.MD5.ToString())
{
if (user.Password.Equals(MD5Encryption.Encrypt(password))) return;
}
else
{
if (CryptogramHelper.Decrypt(user.Password).Equals(password)) return;
}
_sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
throw Oops.Oh(ErrorCodeEnum.D1000);
}
/// <summary>
/// 验证锁屏密码 🔖
/// </summary>
/// <param name="password"></param>
/// <returns></returns>
[DisplayName("验证锁屏密码")]
public virtual async Task<bool> UnLockScreen([Required, FromQuery] string password)
{
// 账号是否存在
var user = await _sysUserRep.GetFirstAsync(u => u.Id == _userManager.UserId);
_ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{user.Account}";
var passwordErrorTimes = _sysCacheService.Get<int>(keyPasswordErrorTimes);
// 是否开启域登录验证
if (await _sysConfigService.GetConfigValueByCode<bool>(ConfigConst.SysDomainLogin))
{
var userLdap = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysUserLdap>>().GetFirstAsync(u => u.UserId == user.Id && u.TenantId == user.TenantId);
if (userLdap == null)
{
VerifyPassword(password, keyPasswordErrorTimes, passwordErrorTimes, user);
}
else if (!await App.GetRequiredService<SysLdapService>().AuthAccount(user.TenantId.Value, userLdap.Account, CryptogramHelper.Decrypt(password)))
{
_sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
throw Oops.Oh(ErrorCodeEnum.D1000);
}
}
else
VerifyPassword(password, keyPasswordErrorTimes, passwordErrorTimes, user);
return true;
}
/// <summary>
/// 手机号登录 🔖
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[DisplayName("手机号登录")]
[AllowAnonymous]
public virtual async Task<LoginOutput> LoginPhone([Required] LoginPhoneInput input)
{
// 校验短信验证码
App.GetRequiredService<SysSmsService>().VerifyCode(new SmsVerifyCodeInput { Phone = input.Phone, Code = input.Code });
// 获取并验证账号
var user = await GetLoginUser(input.TenantId, phone: input.Phone);
return await CreateToken(user);
}
/// <summary>
/// 生成Token令牌 🔖
/// </summary>
/// <param name="user"></param>
/// <param name="loginMode"></param>
/// <returns></returns>
[NonAction]
public async Task<LoginOutput> CreateToken(SysUser user, LoginModeEnum loginMode = LoginModeEnum.PC)
{
// 单用户登录
await App.GetRequiredService<SysOnlineUserService>().SingleLogin(user.Id, loginMode);
// 生成Token令牌
user.TokenVersion += 1;
var tokenExpire = await _sysConfigService.GetTokenExpire();
var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
{
{ ClaimConst.UserId, user.Id },
{ ClaimConst.TokenVersion, user.TokenVersion },
}, tokenExpire);
// 生成刷新Token令牌
var refreshTokenExpire = await _sysConfigService.GetRefreshTokenExpire();
var refreshToken = JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);
// 设置响应报文头
_httpContextAccessor.HttpContext.SetTokensOfResponseHeaders(accessToken, refreshToken);
// Swagger Knife4UI-AfterScript登录脚本
// ke.global.setAllHeader('Authorization', 'Bearer ' + ke.response.headers['access-token']);
// 更新用户登录信息
user.LastLoginIp = _httpContextAccessor.HttpContext.GetRemoteIpAddressToIPv4(true);
(user.LastLoginAddress, double? longitude, double? latitude) = CommonHelper.GetIpAddress(user.LastLoginIp);
user.LastLoginTime = DateTime.Now;
user.LastLoginDevice = CommonHelper.GetClientDeviceInfo(_httpContextAccessor.HttpContext?.Request?.Headers?.UserAgent);
await _sysUserRep.AsUpdateable(user).UpdateColumns(u => new
{
u.TokenVersion,
u.LastLoginIp,
u.LastLoginAddress,
u.LastLoginTime,
u.LastLoginDevice,
}).ExecuteCommandAsync();
// 缓存用户Token版本
_sysCacheService.Set($"{CacheConst.KeyUserToken}{user.Id}", $"{user.TokenVersion}");
// 发布系统登录事件
await _eventPublisher.PublishAsync(UserEventTypeEnum.Login, user);
// 缓存用户状态
await SetUserManager(user, loginMode);
return new LoginOutput
{
AccessToken = accessToken,
RefreshToken = refreshToken
};
}
/// <summary>
/// 设置用户状态
/// </summary>
/// <param name="user"></param>
/// <param name="loginMode"></param>
private async Task SetUserManager(SysUser user, LoginModeEnum loginMode = LoginModeEnum.PC)
{
var db = _sysUserRep.Context.CopyNew();
user.SysPos ??= await db.Queryable<SysPos>().FirstAsync(u => u.Id == user.PosId);
user.SysOrg ??= await db.Queryable<SysOrg>().FirstAsync(u => u.Id == user.OrgId);
var roleIds = await db.Queryable<SysRole>().InnerJoinIF<SysUserRole>(user.AccountType != AccountTypeEnum.SuperAdmin, (u, a) => a.RoleId == u.Id && a.UserId == user.Id).Select((u, a) => u.Id).ToListAsync();
var posIds = await db.Queryable<SysPos>().InnerJoinIF<SysUserExtOrg>(user.AccountType != AccountTypeEnum.SuperAdmin, (u, a) => a.PosId == u.Id && a.UserId == user.Id).Select((u, a) => u.Id).ToListAsync();
posIds = posIds.Concat([user.PosId]).Where(u => u != 0).ToList();
var menuIds = await db.Queryable<SysMenu>().InnerJoinIF<SysRoleMenu>(user.AccountType != AccountTypeEnum.SuperAdmin, (u, a) => a.MenuId == u.Id && roleIds.Contains(a.RoleId))
.Where(u => u.Status == StatusEnum.Enable)
.Select((u, a) => u.Id)
.ToListAsync();
var maxDataScope = await db.Queryable<SysRole>().Where(u => roleIds.Contains(u.Id)).Select(u => u.DataScope).ToListAsync();
if (!maxDataScope.Any()) maxDataScope = [DataScopeEnum.Self];
var orgIds = GetUserOrgIdList(user, roleIds);
var permissions = GetUserPermissions(user, roleIds);
var unauthorizedPermissions = GetUserUnPermissions(user, roleIds);
// 缓存用户状态
_userManager.Set(new()
{
UserId = user.Id,
TenantId = user.TenantId,
Account = user.Account,
RealName = user.RealName,
NickName = user.NickName,
AccountType = user.AccountType,
OrgId = user.OrgId,
OrgCode = user.SysOrg?.Code,
OrgName = user.SysOrg?.Name,
OrgType = user.SysOrg?.Type,
OrgLevel = user.SysOrg?.Level,
PosId = user.PosId,
PosName = user.SysPos?.Name,
PosCode = user.SysPos?.Code,
LoginMode = loginMode,
TokenVersion = user.TokenVersion,
OrgIds = orgIds,
PosIds = posIds,
RoleIds = roleIds,
MenuIds = menuIds,
Permissions = permissions,
UnauthorizedPermissions = unauthorizedPermissions,
DataScopeList = user.AccountType == AccountTypeEnum.SuperAdmin ? [DataScopeEnum.All] : maxDataScope,
AppPermissions = loginMode == LoginModeEnum.APP ? LazyHelper.GetService<SysCommonService>().Value.GetAppApiList() : null,
ExtProps = App.GetServices<IUserManagerExtProps>()?.SelectMany(u => u.GetInitExtProps(user)).Where(u => !string.IsNullOrWhiteSpace(u.Key)).ToDictionary(u => u.Key, u => u.Value)
});
}
/// <summary>
/// 获取当前登陆用户信息 🔖
/// </summary>
/// <returns></returns>
[DisplayName("获取当前登陆用户信息")]
public virtual async Task<LoginUserOutput> GetUserInfo()
{
var user = await _sysUserRep.GetByIdAsync(_userManager.UserId) ?? throw Oops.Oh(ErrorCodeEnum.D1011).StatusCode(401);
// 机构
var org = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysOrg>>().GetByIdAsync(user.OrgId);
// 职位
var pos = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysPos>>().GetByIdAsync(user.PosId);
// 角色集合
var roles = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysUserRole>>().AsQueryable()
.LeftJoin<SysRole>((u, a) => u.RoleId == a.Id)
.Where(u => u.UserId == user.Id)
.Select((u, a) => new RoleDto { Id = a.Id, Name = a.Name, Code = a.Code }).ToListAsync();
// 个性化水印文字(若系统水印为空则不显示)
var watermarkText = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().AsQueryable().Where(u => u.Id == user.TenantId).Select(u => u.Watermark).FirstAsync();
if (!string.IsNullOrWhiteSpace(watermarkText))
watermarkText += $"-{user.RealName}"; // $"-{user.RealName}-{_httpContextAccessor.HttpContext.GetRemoteIpAddressToIPv4(true)}-{DateTime.Now}";
return new LoginUserOutput
{
Id = user.Id,
TenantId = user.TenantId,
Account = user.Account,
RealName = user.RealName,
Phone = user.Phone,
IdCardNum = user.IdCardNum,
Email = user.Email,
AccountType = user.AccountType,
Avatar = user.Avatar,
Address = user.Address,
Signature = user.Signature,
OrgId = user.OrgId,
OrgName = org?.Name,
OrgType = org?.Type,
PosName = pos?.Name,
Apis = _userManager.Permissions,
Roles = roles,
WatermarkText = watermarkText,
LastChangePasswordTime = user.LastChangePasswordTime
};
}
///// <summary>
///// 获取刷新Token 🔖
///// </summary>
///// <param name="accessToken"></param>
///// <returns></returns>
//[DisplayName("获取刷新Token")]
//public string GetRefreshToken([FromQuery] string accessToken)
//{
// var refreshTokenExpire = _sysConfigService.GetRefreshTokenExpire().GetAwaiter().GetResult();
// return JWTEncryption.GenerateRefreshToken(accessToken, refreshTokenExpire);
//}
/// <summary>
/// 退出系统 🔖
/// </summary>
[DisplayName("退出系统")]
public async Task Logout()
{
var httpContext = _httpContextAccessor.HttpContext ?? throw Oops.Oh(ErrorCodeEnum.D1016);
var userId = httpContext.User.FindFirst(ClaimConst.UserId)?.Value;
var version = httpContext.User.FindFirst(ClaimConst.TokenVersion)?.Value;
if (string.IsNullOrWhiteSpace(userId) || string.IsNullOrWhiteSpace(version) || string.IsNullOrWhiteSpace(_userManager.Account))
throw Oops.Oh(ErrorCodeEnum.D1011);
// 写入Token黑名单
var tokenExpire = await _sysConfigService.GetTokenExpire();
_sysCacheService.Set($"{CacheConst.KeyTokenBlacklist}{userId}:{version}", _userManager.Account, TimeSpan.FromMinutes(tokenExpire));
// 发布系统退出事件
await _eventPublisher.PublishAsync(UserEventTypeEnum.Logout, _userManager);
// 退出Swagger/设置无效Token响应头
_httpContextAccessor.HttpContext.SignoutToSwagger();
}
/// <summary>
/// 获取验证码 🔖
/// </summary>
/// <returns></returns>
[SuppressMonitor]
[DisplayName("获取验证码")]
[AllowAnonymous]
public CaptchaOutput GetCaptcha()
{
var codeId = YitIdHelper.NextId().ToString();
var captcha = _captcha.Generate(codeId);
var expirySeconds = App.GetOptions<CaptchaOptions>()?.ExpirySeconds ?? 60;
return new CaptchaOutput { Id = codeId, Img = captcha.Base64, ExpirySeconds = expirySeconds };
}
/// <summary>
/// Swagger登录检查 🔖
/// </summary>
/// <returns></returns>
[Route("/api/swagger/checkUrl"), NonUnify]
[ApiDescriptionSettings(Description = "Swagger登录检查", DisableInherite = true)]
[AllowAnonymous]
public int SwaggerCheckUrl()
{
return _httpContextAccessor.HttpContext.User.Identity.IsAuthenticated ? 200 : 401;
}
/// <summary>
/// Swagger登录提交 🔖
/// </summary>
/// <param name="auth"></param>
/// <returns></returns>
[Route("/api/swagger/submitUrl"), NonUnify]
[ApiDescriptionSettings(Description = "Swagger登录提交", DisableInherite = true)]
[AllowAnonymous]
public async Task<int> SwaggerSubmitUrl([FromForm] SpecificationAuth auth)
{
try
{
// 关闭默认租户验证码验证
var tenantList = _sysCacheService.Get<List<SysTenant>>(CacheConst.KeyTenant);
var tenant = tenantList.FirstOrDefault(u => u.Id == SqlSugarConst.DefaultTenantId);
var tmpCaptcha = tenant.Captcha;
tenant.Captcha = false;
_sysCacheService.Set(CacheConst.KeyTenant, tenantList);
await Login(new LoginInput
{
Account = auth.UserName,
Password = CryptogramHelper.SM2Encrypt(auth.Password),
TenantId = SqlSugarConst.DefaultTenantId
});
// 恢复默认租户验证码状态
tenant.Captcha = tmpCaptcha;
_sysCacheService.Set(CacheConst.KeyTenant, tenantList);
return 200;
}
catch (Exception)
{
return 401;
}
}
/// <summary>
/// 获取系统所有接口列表
/// </summary>
[NonAction]
public List<ApiOutput> GetSysAllApiInfoList()
{
return _sysCacheService.GetOrAdd(CacheConst.KeyAllApi, _ =>
{
var apiList = new List<ApiOutput>();
var apiDescriptionGroups = _apiProvider.ApiDescriptionGroups.Items;
foreach (ApiDescriptionGroup group in apiDescriptionGroups)
{
foreach (var action in group.Items)
{
// 控制器信息
if (action.ActionDescriptor is not ControllerActionDescriptor actionDescriptor) continue;
var apiDescription = actionDescriptor.ControllerTypeInfo.GetCustomAttribute<ApiDescriptionSettingsAttribute>(true);
// 路由
var route = action.RelativePath!.Contains('{') ? action.RelativePath[..(action.RelativePath.IndexOf('{') - 1)] : action.RelativePath; // 去掉路由参数
route = route[(route.IndexOf('/') + 1)..]; // 去掉路由前缀
// 获取分组名称和接口名称
string groupName = null, displayText = null;
foreach (var attr in action.ActionDescriptor.EndpointMetadata)
{
switch (attr)
{
case ApiDescriptionSettingsAttribute settings:
if (!string.IsNullOrWhiteSpace(settings.GroupName)) groupName = settings.GroupName;
break;
case DisplayNameAttribute displayName:
if (!string.IsNullOrWhiteSpace(displayName.DisplayName)) displayText = displayName.DisplayName;
break;
}
}
apiList.Add(new ApiOutput
{
Route = route,
HttpMethod = action.HttpMethod,
Order = apiDescription?.Order ?? 0,
Action = actionDescriptor.ActionName,
Name = actionDescriptor.ControllerName,
GroupName = groupName ?? group.GroupName,
IsAppApi = actionDescriptor.ControllerTypeInfo.GetCustomAttribute<AppApiDescriptionAttribute>(true) != null,
Desc = displayText ?? (string.IsNullOrWhiteSpace(apiDescription?.Description) ? actionDescriptor.ControllerName : apiDescription?.Description),
});
}
}
return apiList;
});
}
/// <summary>
/// 获取用户权限
/// </summary>
/// <param name="user"></param>
/// <param name="roleIds"></param>
/// <returns></returns>
private List<string> GetUserPermissions(SysUser user, List<long> roleIds)
{
var superAdmin = user.AccountType == AccountTypeEnum.SuperAdmin;
var db = _sysUserRep.Context.CopyNew();
var allApi = GetSysAllApiInfoList().Select(u => u.Route).ToArray();
var menuPermissions = db.Queryable<SysMenu>()
.Where(u => u.Status == StatusEnum.Enable && u.Type == MenuTypeEnum.Btn)
.Select(u => u.Permission)
.Distinct()
.ToList();
// 超管返回所有权限
if (superAdmin) return allApi.Union(menuPermissions).Distinct().Order().ToList();
// 普通用户返回已授权标识 + 未不在菜单中的权限标识
var permissions = db.Queryable<SysMenu>()
.InnerJoin<SysRoleMenu>((u, a) => u.Id == a.MenuId)
.Where((u, a) => u.Status == StatusEnum.Enable && u.Type == MenuTypeEnum.Btn)
.Where((u, a) => roleIds.Contains(a.RoleId) && SqlFunc.Subqueryable<SysRoleApi>()
.Where(z => roleIds.Contains(z.RoleId) && u.Permission == z.Route).NotAny())
.Select(u => u.Permission)
.Distinct()
.ToList();
return allApi.Except(menuPermissions).Union(permissions).Distinct().Order().ToList();
}
/// <summary>
/// 获取用户不能访问的权限
/// </summary>
/// <param name="user"></param>
/// <param name="roleIds"></param>
/// <returns></returns>
private List<string> GetUserUnPermissions(SysUser user, List<long> roleIds)
{
var superAdmin = user.AccountType == AccountTypeEnum.SuperAdmin;
var db = _sysUserRep.Context.CopyNew();
if (superAdmin) return [];
return db.Union(db.Queryable<SysMenu>()
.InnerJoin<SysRoleMenu>((u, a) => u.Id == a.MenuId)
.Where((u, a) => u.Status == StatusEnum.Enable && u.Type == MenuTypeEnum.Btn)
.Where((u, a) => !roleIds.Contains(a.RoleId))
.Select(u => u.Permission),
db.Queryable<SysRoleApi>().Where(u => roleIds.Contains(u.RoleId)).Select(u => u.Route))
.ToList();
}
/// <summary>
/// 获取用户已授权的机构Id
/// </summary>
/// <param name="user"></param>
/// <param name="roleIds"></param>
/// <returns></returns>
private List<long> GetUserOrgIdList(SysUser user, List<long> roleIds)
{
var db = _sysUserRep.Context.CopyNew();
var orgIds = db.Union(
// 获取用户表中的机构Id
db.Queryable<SysUser>().IgnoreTenant().Select(u => new { UserId = u.Id, u.OrgId }),
// 获取用户创建的机构Id
db.Queryable<SysOrg>().IgnoreTenant().Where(u => u.CreateUserId != null).Select(u => new { UserId = u.CreateUserId.Value, OrgId = u.Id }),
// 获取用户扩展机构Id
db.Queryable<SysUserExtOrg>().Select(u => new { u.UserId, u.OrgId }),
// 获取用户角色关联的机构Id
db.Queryable<SysRoleOrg>().InnerJoin<SysUserRole>((u, a) => u.RoleId == a.RoleId).Select((u, a) => new { a.UserId, u.OrgId }),
// 获取包含全部数据权限的机构Id
db.Queryable<SysOrg>().IgnoreTenant().Where(u => SqlFunc.Subqueryable<SysUserRole>().InnerJoin<SysRole>((x, y) => x.RoleId == y.Id).Where((x, y) => x.UserId == user.Id && y.DataScope == DataScopeEnum.All).Any()).Select(u => new { UserId = user.Id, OrgId = u.Id }),
// 超管获取全部机构Id
db.Queryable<SysOrg>().IgnoreTenant().Where(u => user.AccountType == AccountTypeEnum.SuperAdmin).Select(u => new { UserId = user.Id, OrgId = u.Id }))
.Where(u => SqlFunc.IsNull(u.OrgId, 0) != 0 && u.UserId == user.Id)
.Select(u => u.OrgId)
.Distinct()
.ToList();
// 如果存在本部门及以下则获取本部门及以下机构的Id
var dataScopes = db.Queryable<SysRole>().Where(u => roleIds.Contains(u.Id)).Select(u => u.DataScope).Distinct().ToList();
if (dataScopes.All(u => u != DataScopeEnum.All) && dataScopes.Any(u => u == DataScopeEnum.DeptChild))
{
var childOrg = db.Queryable<SysOrg>().IgnoreTenant().ToTree(u => u.Children, u => u.Pid, user.OrgId);
if (childOrg is not { Count: > 0 }) return orgIds;
var queue = new Queue<SysOrg>(childOrg);
while (queue.Count > 0)
{
var org = queue.Dequeue();
if (org.Children is { Count: > 0 }) queue.EnqueueRange(org.Children);
orgIds.Add(org.Id);
}
}
return orgIds;
}
/// <summary>
/// 刷新用户状态
/// </summary>
/// <param name="userId"></param>
[NonAction]
public async Task RefreshUserManager(long userId)
{
var user = await _sysUserRep.AsQueryable().IgnoreTenant().Includes(u => u.SysOrg).FirstAsync(u => u.Id == userId);
await SetUserManager(user, CommonHelper.IsMobile(_httpContextAccessor.HttpContext?.Request.Headers.UserAgent ?? "") ? LoginModeEnum.APP : LoginModeEnum.PC);
}
}