😎1、调整登录逻辑 2、清理无效代码
This commit is contained in:
parent
d6b96fb751
commit
dc551bc59c
@ -99,7 +99,7 @@ public class AppAuthService : IDynamicApiController, ITransient
|
||||
// 登录成功则清空密码错误次数
|
||||
_sysCacheService.Remove(keyPasswordErrorTimes);
|
||||
|
||||
return await CreateToken(user, input.LoginMode);
|
||||
return await CreateToken(user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -148,7 +148,7 @@ public class AppAuthService : IDynamicApiController, ITransient
|
||||
var user = await _sysUserRep.AsQueryable().Includes(u => u.SysOrg).ClearFilter().FirstAsync(u => u.Phone.Equals(input.Phone));
|
||||
_ = user ?? throw Oops.Oh(ErrorCodeEnum.D0009);
|
||||
|
||||
return await CreateToken(user, input.LoginMode);
|
||||
return await CreateToken(user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -158,7 +158,7 @@ public class AppAuthService : IDynamicApiController, ITransient
|
||||
/// <param name="loginMode"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public virtual async Task<LoginOutput> CreateToken(SysUser user, LoginModeEnum loginMode)
|
||||
public virtual async Task<LoginOutput> CreateToken(SysUser user, LoginModeEnum loginMode = LoginModeEnum.APP)
|
||||
{
|
||||
// 单用户登录
|
||||
await _sysOnlineUserService.SingleLogin(user.Id, loginMode);
|
||||
|
||||
@ -68,13 +68,16 @@ public class DictAttribute : ValidationAttribute, ITransient
|
||||
return ValidationResult.Success;
|
||||
}
|
||||
|
||||
// 先尝试从 ValidationContext 的依赖注入容器中拿服务,再从全局的 App 容器中获取
|
||||
if (validationContext.GetService(typeof(SysDictDataService)) is not SysDictDataService sysDictDataService)
|
||||
sysDictDataService = App.GetRequiredService<SysDictDataService>();
|
||||
// 先尝试从 ValidationContext 的依赖注入容器中拿服务,拿不到或类型不匹配时,再从全局的 App 容器中获取
|
||||
if (validationContext.GetService(typeof(SysDictTypeService)) is not SysDictTypeService sysDictDataService)
|
||||
sysDictDataService = App.GetRequiredService<SysDictTypeService>();
|
||||
|
||||
// 获取字典值列表
|
||||
var dictDataList = sysDictDataService.GetDataList(DictTypeCode).GetAwaiter().GetResult();
|
||||
var dictDataList = sysDictDataService.GetDataList(new GetDataDictTypeInput { Code = DictTypeCode }).GetAwaiter().GetResult();
|
||||
|
||||
// 使用 HashSet 来提高查找效率
|
||||
var dictHash = new HashSet<string>(dictDataList.Select(u => u.Code));
|
||||
|
||||
if (!dictHash.Contains(valueAsString)) return new ValidationResult($"提示:{ErrorMessage}|字典【{DictTypeCode}】不包含【{valueAsString}】!");
|
||||
|
||||
return ValidationResult.Success;
|
||||
|
||||
@ -26,11 +26,6 @@ public class SqlSugarConst
|
||||
/// </summary>
|
||||
public const string PrimaryKey = "Id";
|
||||
|
||||
/// <summary>
|
||||
/// 默认应用Id
|
||||
/// </summary>
|
||||
public const long DefaultAppId = 1300000000001;
|
||||
|
||||
/// <summary>
|
||||
/// 默认租户Id
|
||||
/// </summary>
|
||||
|
||||
@ -1,82 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统应用表
|
||||
/// </summary>
|
||||
[SysTable]
|
||||
[SugarTable(null, "系统应用表")]
|
||||
public partial class SysApp : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "名称", Length = 32), Required, MaxLength(32)]
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "图标", Length = 256), Required, MaxLength(256)]
|
||||
public virtual string? Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "标题", Length = 32), MaxLength(32)]
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副标题
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "副标题", Length = 32), MaxLength(32)]
|
||||
public string ViceTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副描述
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "副描述", Length = 64), MaxLength(64)]
|
||||
public string? ViceDesc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 水印
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "水印", Length = 32), MaxLength(32)]
|
||||
public string? Watermark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 版权信息
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "版权信息", Length = 64), MaxLength(64)]
|
||||
public string? Copyright { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ICP备案号
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "ICP备案号", Length = 32), MaxLength(32)]
|
||||
public string? Icp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
[IgnoreUpdateSeedColumn]
|
||||
[SugarColumn(ColumnDescription = "排序")]
|
||||
public int OrderNo { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "备注", Length = 256), MaxLength(256)]
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用租户
|
||||
/// </summary>
|
||||
[Navigate(NavigateType.OneToMany, nameof(SysTenant.AppId))]
|
||||
public List<SysTenant> TenantList { get; set; }
|
||||
}
|
||||
@ -1,41 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统应用菜单表
|
||||
/// </summary>
|
||||
[SugarTable(null, "系统应用菜单表")]
|
||||
[SysTable]
|
||||
public partial class SysAppMenu : EntityBaseId
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "应用Id")]
|
||||
public long AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[Navigate(NavigateType.OneToOne, nameof(AppId))]
|
||||
public SysApp SysApp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "菜单Id")]
|
||||
public long MenuId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 菜单
|
||||
/// </summary>
|
||||
[Navigate(NavigateType.OneToOne, nameof(MenuId))]
|
||||
public SysMenu SysMenu { get; set; }
|
||||
}
|
||||
@ -14,23 +14,9 @@ namespace Admin.NET.Core;
|
||||
public partial class SysTenant : EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用Id
|
||||
/// 租管用户Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "应用Id", DefaultValue = "1300000000001")]
|
||||
public long? AppId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 应用
|
||||
/// </summary>
|
||||
[Newtonsoft.Json.JsonIgnore]
|
||||
[System.Text.Json.Serialization.JsonIgnore]
|
||||
[Navigate(NavigateType.OneToOne, nameof(AppId))]
|
||||
public SysApp SysApp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户Id
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "用户Id")]
|
||||
[SugarColumn(ColumnDescription = "租管用户Id")]
|
||||
public long UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -21,18 +21,18 @@ public enum GenderEnum
|
||||
/// <summary>
|
||||
/// 男性
|
||||
/// </summary>
|
||||
[Description("男性")]
|
||||
[Description("男性"), Theme("success")]
|
||||
Male = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 女性
|
||||
/// </summary>
|
||||
[Description("女性")]
|
||||
[Description("女性"), Theme("danger")]
|
||||
Female = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 未说明的性别
|
||||
/// </summary>
|
||||
[Description("未说明的性别"), Theme("info")]
|
||||
[Description("未说明的性别"), Theme("warning")]
|
||||
Unspecified = 9
|
||||
}
|
||||
@ -58,5 +58,17 @@ public enum UserEventTypeEnum
|
||||
/// 解除登录锁定
|
||||
/// </summary>
|
||||
[Description("解除登录锁定")]
|
||||
UnlockLogin = 7
|
||||
UnlockLogin = 7,
|
||||
|
||||
/// <summary>
|
||||
/// 系统登录
|
||||
/// </summary>
|
||||
[Description("系统登录")]
|
||||
Login = 8,
|
||||
|
||||
/// <summary>
|
||||
/// 系统退出
|
||||
/// </summary>
|
||||
[Description("系统退出")]
|
||||
Logout = 9,
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统应用菜单表种子数据
|
||||
/// </summary>
|
||||
public class SysAppMenuSeedData : ISqlSugarEntitySeedData<SysAppMenu>
|
||||
{
|
||||
/// <summary>
|
||||
/// 种子数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<SysAppMenu> HasData()
|
||||
{
|
||||
long id = SqlSugarConst.DefaultAppId;
|
||||
return new SysMenuSeedData().HasData().Select(u => new SysAppMenu { Id = id++, AppId = SqlSugarConst.DefaultAppId, MenuId = u.Id });
|
||||
}
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 系统应用表种子数据
|
||||
/// </summary>
|
||||
public class SysAppSeedData : ISqlSugarEntitySeedData<SysApp>
|
||||
{
|
||||
/// <summary>
|
||||
/// 种子数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<SysApp> HasData()
|
||||
{
|
||||
return
|
||||
[
|
||||
new SysApp{ Id=SqlSugarConst.DefaultAppId, Name="默认应用", Logo="/upload/logo.png", Title="Admin.NET", ViceTitle="Admin.NET", ViceDesc="站在巨人肩膀上的 .NET 通用权限开发框架", Watermark="Admin.NET", Copyright="Copyright \u00a9 2021-present Admin.NET All rights reserved.", Icp="省ICP备12345678号", Remark="系统默认应用", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -21,7 +21,19 @@ public class SysTenantSeedData : ISqlSugarEntitySeedData<SysTenant>
|
||||
|
||||
return
|
||||
[
|
||||
new SysTenant{ Id=SqlSugarConst.DefaultTenantId, AppId=SqlSugarConst.DefaultTenantId, OrgId=SqlSugarConst.DefaultTenantId, UserId=1300000000111, Host="gitee.com", TenantType=TenantTypeEnum.Id, DbType=defaultDbConfig.DbType, Connection=defaultDbConfig.ConnectionString, ConfigId=SqlSugarConst.MainConfigId, Remark="系统默认", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
|
||||
new SysTenant
|
||||
{
|
||||
Id=SqlSugarConst.DefaultTenantId,
|
||||
OrgId=SqlSugarConst.DefaultTenantId,
|
||||
UserId=1300000000111,
|
||||
Host="gitee.com",
|
||||
TenantType=TenantTypeEnum.Id,
|
||||
DbType=defaultDbConfig.DbType,
|
||||
Connection=defaultDbConfig.ConnectionString,
|
||||
ConfigId=SqlSugarConst.MainConfigId,
|
||||
Remark="系统默认",
|
||||
CreateTime=DateTime.Parse("2022-02-10 00:00:00")
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -23,11 +23,11 @@ public class SysUserSeedData : ISqlSugarEntitySeedData<SysUser>
|
||||
return
|
||||
[
|
||||
new SysUser{ Id=1300000000101, Account="superadmin", Password=encryptPassword, NickName="超级管理员", RealName="超级管理员", Phone="18012345678", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Male, AccountType=AccountTypeEnum.SuperAdmin, Remark="超级管理员", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), TenantId=SqlSugarConst.DefaultTenantId },
|
||||
new SysUser{ Id=1300000000111, Account="admin", Password=encryptPassword, NickName="系统管理员", RealName="系统管理员", Phone="18012345678", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Male, AccountType=AccountTypeEnum.SysAdmin, Remark="系统管理员", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=SqlSugarConst.DefaultTenantId, PosId=1300000000102, TenantId=SqlSugarConst.DefaultTenantId },
|
||||
new SysUser{ Id=1300000000112, Account="user1", Password=encryptPassword, NickName="部门主管", RealName="部门主管", Phone="18012345678", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.NormalUser, Remark="部门主管", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=SqlSugarConst.DefaultTenantId + 1, PosId=1300000000108, TenantId=SqlSugarConst.DefaultTenantId },
|
||||
new SysUser{ Id=1300000000113, Account="user2", Password=encryptPassword, NickName="部门职员", RealName="部门职员", Phone="18012345678", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.NormalUser, Remark="部门职员", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=SqlSugarConst.DefaultTenantId + 2, PosId=1300000000110, TenantId=SqlSugarConst.DefaultTenantId },
|
||||
new SysUser{ Id=1300000000114, Account="user3", Password=encryptPassword, NickName="普通用户", RealName="普通用户", Phone="18012345678", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.NormalUser, Remark="普通用户", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=SqlSugarConst.DefaultTenantId + 3, PosId=1300000000115, TenantId=SqlSugarConst.DefaultTenantId },
|
||||
new SysUser{ Id=1300000000115, Account="user4", Password=encryptPassword, NickName="其他", RealName="其他", Phone="18012345678", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.Member, Remark="会员", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=SqlSugarConst.DefaultTenantId + 4, PosId=1300000000116, TenantId=SqlSugarConst.DefaultTenantId },
|
||||
new SysUser{ Id=1300000000111, Account="admin", Password=encryptPassword, NickName="系统管理员", RealName="系统管理员", Phone="18012345677", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Male, AccountType=AccountTypeEnum.SysAdmin, Remark="系统管理员", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=SqlSugarConst.DefaultTenantId, PosId=1300000000102, TenantId=SqlSugarConst.DefaultTenantId },
|
||||
new SysUser{ Id=1300000000112, Account="user1", Password=encryptPassword, NickName="部门主管", RealName="部门主管", Phone="18012345676", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.NormalUser, Remark="部门主管", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=SqlSugarConst.DefaultTenantId + 1, PosId=1300000000108, TenantId=SqlSugarConst.DefaultTenantId },
|
||||
new SysUser{ Id=1300000000113, Account="user2", Password=encryptPassword, NickName="部门职员", RealName="部门职员", Phone="18012345675", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.NormalUser, Remark="部门职员", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=SqlSugarConst.DefaultTenantId + 2, PosId=1300000000110, TenantId=SqlSugarConst.DefaultTenantId },
|
||||
new SysUser{ Id=1300000000114, Account="user3", Password=encryptPassword, NickName="普通用户", RealName="普通用户", Phone="18012345674", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.NormalUser, Remark="普通用户", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=SqlSugarConst.DefaultTenantId + 3, PosId=1300000000115, TenantId=SqlSugarConst.DefaultTenantId },
|
||||
new SysUser{ Id=1300000000115, Account="user4", Password=encryptPassword, NickName="其他", RealName="其他", Phone="18012345673", Birthday=DateTime.Parse("2000-01-01"), Sex=GenderEnum.Female, AccountType=AccountTypeEnum.Member, Remark="会员", CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrgId=SqlSugarConst.DefaultTenantId + 4, PosId=1300000000116, TenantId=SqlSugarConst.DefaultTenantId },
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -1,173 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 应用基础输入参数
|
||||
/// </summary>
|
||||
public class SysAppInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键Id
|
||||
/// </summary>
|
||||
public virtual long? Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "名称不能为空")]
|
||||
public virtual string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "标题不能为空")]
|
||||
public virtual string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副标题
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "副标题不能为空")]
|
||||
public virtual string ViceTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副描述
|
||||
/// </summary>
|
||||
public virtual string? ViceDesc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 水印
|
||||
/// </summary>
|
||||
public virtual string? Watermark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 版权信息
|
||||
/// </summary>
|
||||
public virtual string? Copyright { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ICP备案号
|
||||
/// </summary>
|
||||
public virtual string? Icp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "排序不能为空")]
|
||||
public virtual int? OrderNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public virtual string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public virtual string? Logo { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加应用输入参数
|
||||
/// </summary>
|
||||
public class AddSysAppInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "Logo不能为空")]
|
||||
public string Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "名称不能为空")]
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "标题不能为空")]
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副标题
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "副标题不能为空")]
|
||||
public string ViceTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副描述
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "副描述不能为空")]
|
||||
public string ViceDesc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 水印
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "水印不能为空")]
|
||||
public string Watermark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 版权信息
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "版权信息不能为空")]
|
||||
public string Copyright { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ICP备案号
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "备案号不能为空")]
|
||||
public string Icp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "排序不能为空")]
|
||||
public int OrderNo { get; set; } = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[MaxLength(256, ErrorMessage = "备注字符长度不能超过256")]
|
||||
public string Remark { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新应用输入参数
|
||||
/// </summary>
|
||||
public class UpdateSysAppInput : AddSysAppInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "主键Id不能为空")]
|
||||
public long Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 授权应用菜单
|
||||
/// </summary>
|
||||
public class UpdateAppMenuInput : BaseIdInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 菜单Id集合
|
||||
/// </summary>
|
||||
public List<long> MenuIdList { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 租户iId
|
||||
/// </summary>
|
||||
public class ChangeAppInput : BaseIdInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 租户Id
|
||||
/// </summary>
|
||||
[Required(ErrorMessage = "租户不能为空")]
|
||||
public long TenantId { get; set; }
|
||||
}
|
||||
@ -1,103 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 应用输出参数
|
||||
/// </summary>
|
||||
public class SysAppOutput
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键Id
|
||||
/// </summary>
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
public string? Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
public string Title { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副标题
|
||||
/// </summary>
|
||||
public string ViceTitle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 副描述
|
||||
/// </summary>
|
||||
public string? ViceDesc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 水印
|
||||
/// </summary>
|
||||
public string? Watermark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 版权信息
|
||||
/// </summary>
|
||||
public string? Copyright { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// ICP备案号
|
||||
/// </summary>
|
||||
public string? Icp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序
|
||||
/// </summary>
|
||||
public int OrderNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
public DateTime? CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 更新时间
|
||||
/// </summary>
|
||||
public DateTime? UpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建者Id
|
||||
/// </summary>
|
||||
public long? CreateUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建者姓名
|
||||
/// </summary>
|
||||
public string? CreateUserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 修改者Id
|
||||
/// </summary>
|
||||
public long? UpdateUserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 修改者姓名
|
||||
/// </summary>
|
||||
public string? UpdateUserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 软删除
|
||||
/// </summary>
|
||||
public bool IsDelete { get; set; }
|
||||
}
|
||||
@ -1,183 +0,0 @@
|
||||
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
|
||||
//
|
||||
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
|
||||
//
|
||||
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
|
||||
|
||||
namespace Admin.NET.Core.Service;
|
||||
|
||||
/// <summary>
|
||||
/// 系统应用服务 🧩
|
||||
/// </summary>
|
||||
[ApiDescriptionSettings(Name = "SysApp", Order = 495, Description = "系统应用")]
|
||||
public class SysAppService : IDynamicApiController, ITransient
|
||||
{
|
||||
private readonly SqlSugarRepository<SysAppMenu> _sysAppMenuRep;
|
||||
private readonly SqlSugarRepository<SysApp> _sysAppRep;
|
||||
private readonly SysAuthService _sysAuthService;
|
||||
private readonly UserManager _userManager;
|
||||
|
||||
public SysAppService(SqlSugarRepository<SysApp> sysAppRep,
|
||||
SqlSugarRepository<SysAppMenu> sysAppMenuRep,
|
||||
SysAuthService sysAuthService,
|
||||
UserManager userManager)
|
||||
{
|
||||
_sysAppRep = sysAppRep;
|
||||
_userManager = userManager;
|
||||
_sysAppMenuRep = sysAppMenuRep;
|
||||
_sysAuthService = sysAuthService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询应用 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("分页查询应用")]
|
||||
[ApiDescriptionSettings(Name = "Page"), HttpPost]
|
||||
public async Task<SqlSugarPagedList<SysAppOutput>> Page(BasePageInput input)
|
||||
{
|
||||
input.Keyword = input.Keyword?.Trim();
|
||||
var query = _sysAppRep.AsQueryable()
|
||||
.WhereIF(!string.IsNullOrWhiteSpace(input.Keyword), u => u.Name.Contains(input.Keyword) ||
|
||||
u.Title.Contains(input.Keyword) || u.ViceTitle.Contains(input.Keyword) ||
|
||||
u.ViceDesc.Contains(input.Keyword) || u.Remark.Contains(input.Keyword))
|
||||
.OrderBy(u => new { u.OrderNo, u.Id })
|
||||
.Select<SysAppOutput>();
|
||||
return await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加应用 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("增加应用")]
|
||||
[ApiDescriptionSettings(Name = "Add"), HttpPost]
|
||||
public async Task<long> Add(AddSysAppInput input)
|
||||
{
|
||||
var entity = input.Adapt<SysApp>();
|
||||
return await _sysAppRep.InsertAsync(entity) ? entity.Id : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新应用 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("更新应用")]
|
||||
[ApiDescriptionSettings(Name = "Update"), HttpPost]
|
||||
public async Task Update(UpdateSysAppInput input)
|
||||
{
|
||||
_ = await _sysAppRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
|
||||
var entity = input.Adapt<SysApp>();
|
||||
await _sysAppRep.AsUpdateable(entity).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除应用 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("删除应用")]
|
||||
[ApiDescriptionSettings(Name = "Delete"), HttpPost]
|
||||
public async Task Delete(BaseIdInput input)
|
||||
{
|
||||
var entity = await _sysAppRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
|
||||
// 禁止删除存在关联租户的应用
|
||||
if (await _sysAppRep.Context.Queryable<SysTenant>().AnyAsync(u => u.AppId == input.Id)) throw Oops.Oh(ErrorCodeEnum.A1001);
|
||||
|
||||
// 禁止删除存在关联菜单的应用
|
||||
if (await _sysAppMenuRep.AsQueryable().AnyAsync(u => u.AppId == input.Id)) throw Oops.Oh(ErrorCodeEnum.A1002);
|
||||
|
||||
await _sysAppRep.DeleteAsync(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取应用菜单 🔖
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取应用菜单")]
|
||||
public async Task<List<long>> GetMenuList([FromQuery] long id)
|
||||
{
|
||||
return await _sysAppMenuRep.AsQueryable().Where(u => u.AppId == id).Select(u => u.MenuId).ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 授权应用菜单 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[UnitOfWork]
|
||||
[DisplayName("授权应用菜单")]
|
||||
public async Task GrantMenu(UpdateAppMenuInput input)
|
||||
{
|
||||
input.MenuIdList ??= new();
|
||||
|
||||
await _sysAppMenuRep.DeleteAsync(u => u.AppId == input.Id);
|
||||
|
||||
var list = input.MenuIdList.Select(id => new SysAppMenu { AppId = input.Id, MenuId = id }).ToList();
|
||||
|
||||
await _sysAppMenuRep.InsertRangeAsync(list);
|
||||
|
||||
// 清除应用下其他模块越权的授权数据,包括角色菜单,用户收藏菜单
|
||||
var tenantIds = await _sysAppRep.Context.Queryable<SysTenant>().Where(u => u.AppId == input.Id).Select(u => u.Id).ToListAsync();
|
||||
var roleIds = await _sysAppRep.Context.Queryable<SysRole>().Where(u => tenantIds.Contains((long)u.TenantId)).Select(u => u.Id).ToListAsync();
|
||||
var userIds = await _sysAppRep.Context.Queryable<SysUser>().Where(u => tenantIds.Contains((long)u.TenantId)).Select(u => u.Id).ToListAsync();
|
||||
await _sysAppRep.Context.Deleteable<SysRoleMenu>().Where(u => roleIds.Contains(u.RoleId) && !input.MenuIdList.Contains(u.MenuId)).ExecuteCommandAsync();
|
||||
await _sysAppRep.Context.Deleteable<SysUserMenu>().Where(u => userIds.Contains(u.UserId) && !input.MenuIdList.Contains(u.MenuId)).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取应用数据 🔖
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[DisplayName("获取应用数据")]
|
||||
public async Task<dynamic> GetAppData()
|
||||
{
|
||||
var list = await _sysAppRep.AsQueryable().Includes(u => u.TenantList).ToListAsync();
|
||||
return list.Where(u => u.TenantList.Count > 0).Select(u => new
|
||||
{
|
||||
u.Id,
|
||||
Value = u.Id,
|
||||
Label = u.Name,
|
||||
Children = u.TenantList.Select(t => new
|
||||
{
|
||||
t.Id,
|
||||
Value = t.Id,
|
||||
Label = t.Host ?? (t.Id + ""),
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 切换应用 🔖
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[DisplayName("切换应用")]
|
||||
public async Task<LoginOutput> ChangeApp(ChangeAppInput input)
|
||||
{
|
||||
_ = await _sysAppRep.Context.Queryable<SysTenant>().FirstAsync(u => u.Id == input.TenantId) ?? throw Oops.Oh(ErrorCodeEnum.Z1003);
|
||||
_ = await _sysAppRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
|
||||
var user = await _sysAppRep.Context.Queryable<SysUser>().FirstAsync(u => u.Id == _userManager.UserId);
|
||||
user.TenantId = input.TenantId;
|
||||
|
||||
return await _sysAuthService.CreateToken(user, input.Id, LoginModeEnum.PC);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前应用信息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<SysApp> GetCurrentAppInfo()
|
||||
{
|
||||
var appId = _userManager.AppId > 0 ? _userManager.AppId : SqlSugarConst.DefaultAppId;
|
||||
return await _sysAppRep.GetFirstAsync(u => u.Id == appId) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
}
|
||||
}
|
||||
@ -73,5 +73,5 @@ public class LoginPhoneInput
|
||||
/// <summary>
|
||||
/// 登录模式
|
||||
/// </summary>
|
||||
public LoginModeEnum LoginMode { get; set; }
|
||||
public LoginModeEnum LoginMode { get; set; } = LoginModeEnum.PC;
|
||||
}
|
||||
@ -21,13 +21,15 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
private readonly SysCacheService _sysCacheService;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly ICaptcha _captcha;
|
||||
private readonly IEventPublisher _eventPublisher;
|
||||
|
||||
public SysAuthService(UserManager userManager,
|
||||
SqlSugarRepository<SysUser> sysUserRep,
|
||||
SysConfigService sysConfigService,
|
||||
SysCacheService sysCacheService,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
ICaptcha captcha)
|
||||
ICaptcha captcha,
|
||||
IEventPublisher eventPublisher)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_sysUserRep = sysUserRep;
|
||||
@ -35,6 +37,7 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
_sysCacheService = sysCacheService;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_captcha = captcha;
|
||||
_eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -57,21 +60,18 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
// 判断是否开启验证码并校验
|
||||
if (await _sysConfigService.GetConfigValueByCode<bool>(ConfigConst.SysCaptcha) && !_captcha.Validate(input.CodeId.ToString(), input.Code)) throw Oops.Oh(ErrorCodeEnum.D0008);
|
||||
|
||||
// 获取登录租户和用户
|
||||
var (tenant, user) = await GetLoginUserAndTenant(input.TenantId, account: input.Account);
|
||||
|
||||
// 账号是否被冻结
|
||||
if (user.Status == StatusEnum.Disable) throw Oops.Oh(ErrorCodeEnum.D1017);
|
||||
// 获取并验证账号
|
||||
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 == tenant.Id);
|
||||
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(tenant.Id, userLdap.Account, CryptogramUtil.Decrypt(input.Password)))
|
||||
else if (!await App.GetRequiredService<SysLdapService>().AuthAccount(user.TenantId, userLdap.Account, CryptogramUtil.Decrypt(input.Password)))
|
||||
{
|
||||
_sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
|
||||
throw Oops.Oh(ErrorCodeEnum.D1000);
|
||||
@ -83,42 +83,42 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
// 登录成功则清空密码错误次数
|
||||
_sysCacheService.Remove(keyPasswordErrorTimes);
|
||||
|
||||
return await CreateToken(user, tenant.AppId, input.LoginMode);
|
||||
return await CreateToken(user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取登录租户和用户
|
||||
/// 获取登录用户
|
||||
/// </summary>
|
||||
/// <param name="tenantId"></param>
|
||||
/// <param name="account"></param>
|
||||
/// <param name="phone"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<(SysTenant tenant, SysUser user)> GetLoginUserAndTenant(long tenantId, string account = null, string phone = null)
|
||||
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 tenant = await _sysUserRep.ChangeRepository<SqlSugarRepository<SysTenant>>().GetFirstAsync(u => u.Id == tenantId);
|
||||
if (tenant?.Status != StatusEnum.Enable) throw Oops.Oh(ErrorCodeEnum.Z1003);
|
||||
//// 若没有传值租户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).ClearFilter()
|
||||
.Where(u => u.AccountType == AccountTypeEnum.SuperAdmin || u.TenantId == tenantId)
|
||||
//.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.AccountType == AccountTypeEnum.SuperAdmin) user.TenantId = tenantId;
|
||||
// 判断账号是否被冻结
|
||||
if (user.Status == StatusEnum.Disable) throw Oops.Oh(ErrorCodeEnum.D1017);
|
||||
|
||||
return (tenant, user);
|
||||
// 判断租户是否存在及状态
|
||||
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>
|
||||
@ -200,26 +200,21 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
// 校验短信验证码
|
||||
App.GetRequiredService<SysSmsService>().VerifyCode(new SmsVerifyCodeInput { Phone = input.Phone, Code = input.Code });
|
||||
|
||||
// 获取登录租户和用户
|
||||
var (tenant, user) = await GetLoginUserAndTenant(input.TenantId, phone: input.Phone);
|
||||
// 获取并验证账号
|
||||
var user = await GetLoginUser(input.TenantId, phone: input.Phone);
|
||||
|
||||
return await CreateToken(user, tenant.AppId, input.LoginMode);
|
||||
return await CreateToken(user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成Token令牌 🔖
|
||||
/// </summary>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="appId"></param>
|
||||
/// <param name="loginMode"></param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
internal async Task<LoginOutput> CreateToken(SysUser user, long? appId, LoginModeEnum loginMode)
|
||||
internal async Task<LoginOutput> CreateToken(SysUser user, LoginModeEnum loginMode = LoginModeEnum.PC)
|
||||
{
|
||||
// 默认PC端登录模式
|
||||
if (loginMode == 0)
|
||||
loginMode = LoginModeEnum.PC;
|
||||
|
||||
// 单用户登录
|
||||
await App.GetRequiredService<SysOnlineUserService>().SingleLogin(user.Id, loginMode);
|
||||
|
||||
@ -227,7 +222,6 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
var tokenExpire = await _sysConfigService.GetTokenExpire();
|
||||
var accessToken = JWTEncryption.Encrypt(new Dictionary<string, object>
|
||||
{
|
||||
{ ClaimConst.AppId, appId },
|
||||
{ ClaimConst.UserId, user.Id },
|
||||
{ ClaimConst.TenantId, user.TenantId },
|
||||
{ ClaimConst.Account, user.Account },
|
||||
@ -263,6 +257,9 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
u.LastLoginDevice,
|
||||
}).ExecuteCommandAsync();
|
||||
|
||||
// 发布系统登录事件
|
||||
await _eventPublisher.PublishAsync(UserEventTypeEnum.Login, user);
|
||||
|
||||
return new LoginOutput
|
||||
{
|
||||
AccessToken = accessToken,
|
||||
@ -330,11 +327,14 @@ public class SysAuthService : IDynamicApiController, ITransient
|
||||
/// 退出系统 🔖
|
||||
/// </summary>
|
||||
[DisplayName("退出系统")]
|
||||
public void Logout()
|
||||
public async void Logout()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_userManager.Account))
|
||||
throw Oops.Oh(ErrorCodeEnum.D1011);
|
||||
|
||||
// 发布系统退出事件
|
||||
await _eventPublisher.PublishAsync(UserEventTypeEnum.Logout, _userManager);
|
||||
|
||||
_httpContextAccessor.HttpContext.SignoutToSwagger();
|
||||
}
|
||||
|
||||
|
||||
@ -112,7 +112,7 @@ public class SysLdapService : IDynamicApiController, ITransient
|
||||
/// <param name="tenantId">租户</param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<bool> AuthAccount(long tenantId, string account, string password)
|
||||
public async Task<bool> AuthAccount(long? tenantId, string account, string password)
|
||||
{
|
||||
var sysLdap = await _sysLdapRep.GetFirstAsync(u => u.TenantId == tenantId) ?? throw Oops.Oh(ErrorCodeEnum.D1002);
|
||||
var ldapConn = new LdapConnection();
|
||||
|
||||
@ -113,7 +113,7 @@ public class SysOAuthService : IDynamicApiController, ITransient
|
||||
}
|
||||
|
||||
// 构建Token令牌,默认回调登录为PC模式
|
||||
var token = await App.GetRequiredService<SysAuthService>().CreateToken(wechatUser.SysUser, SqlSugarConst.DefaultAppId, LoginModeEnum.PC);
|
||||
var token = await App.GetRequiredService<SysAuthService>().CreateToken(wechatUser.SysUser);
|
||||
|
||||
return new RedirectResult($"{redirectUrl}/#/login?token={token.AccessToken}");
|
||||
}
|
||||
|
||||
@ -45,8 +45,8 @@ public class ExcelHelper
|
||||
Task.WhenAll(tasks).GetAwaiter().GetResult();
|
||||
|
||||
// 仅导出错误记录
|
||||
var errorList = result.Where(u => !string.IsNullOrWhiteSpace(u.Error));
|
||||
return ExportData(errorList.Any() ? errorList : []);
|
||||
var errorList = result.Where(u => !string.IsNullOrWhiteSpace(u.Error)).ToList();
|
||||
return ExportData(errorList.Count != 0 ? errorList : []);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
"name": "admin.net.pro",
|
||||
"type": "module",
|
||||
"version": "2.4.33",
|
||||
"lastBuildTime": "2025.01.14",
|
||||
"lastBuildTime": "2025.01.15",
|
||||
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
|
||||
"author": "zuohuaijun",
|
||||
"license": "MIT",
|
||||
@ -39,7 +39,7 @@
|
||||
"element-plus": "^2.9.3",
|
||||
"exceljs": "^4.4.0",
|
||||
"ezuikit-js": "^8.1.4",
|
||||
"gcoord": "^1.0.6",
|
||||
"gcoord": "^1.0.7",
|
||||
"js-cookie": "^3.0.5",
|
||||
"js-table2excel": "^1.1.2",
|
||||
"jsplumb": "^2.15.6",
|
||||
@ -100,7 +100,7 @@
|
||||
"less": "^4.2.1",
|
||||
"prettier": "^3.4.2",
|
||||
"rollup-plugin-visualizer": "^5.14.0",
|
||||
"sass": "^1.83.3",
|
||||
"sass": "^1.83.4",
|
||||
"terser": "^5.37.0",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^6.0.7",
|
||||
|
||||
@ -182,7 +182,7 @@ const onHandleCommandClick = (path: string) => {
|
||||
showCancelButton: true,
|
||||
confirmButtonText: t('message.user.logOutConfirm'),
|
||||
cancelButtonText: t('message.user.logOutCancel'),
|
||||
buttonSize: 'default',
|
||||
// buttonSize: 'default',
|
||||
beforeClose: async (action, instance, done) => {
|
||||
if (action === 'confirm') {
|
||||
instance.confirmButtonLoading = true;
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<el-tabs v-model="activeTab" class="demo-tabs">
|
||||
<el-tab-pane label="代码生成" name="codeGen" style="height: 600px">
|
||||
<el-tab-pane label="代码生成" name="codeGen" style="height: 700px">
|
||||
<div style="color: red; padding: 10px 10px; background: #faecd8; margin-bottom: 10px">
|
||||
<el-icon style="transform: translateY(2px)"><ele-Bell /></el-icon>
|
||||
<span> 若找不到在前端生成的实体/表,请检查配置文件中实体所在程序集或重启后台服务。 </span>
|
||||
@ -73,13 +73,6 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="Name字段" prop="treeName" :rules="[{ required: true, message: '请选择树控件Name字段', trigger: 'blur' }]">
|
||||
<el-select v-model="state.ruleForm.treeName" @change="treeNameChanged" value-key="value" filterable clearable class="w100">
|
||||
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="业务名" prop="busName" :rules="[{ required: true, message: '业务名不能为空', trigger: 'blur' }]">
|
||||
<el-input v-model="state.ruleForm.busName" placeholder="请输入" clearable />
|
||||
@ -213,21 +206,31 @@
|
||||
</template>
|
||||
</el-col> -->
|
||||
<el-col>
|
||||
<el-divider content-position="center"> 左边布局显示树形列表;右边布局上下结构显示主子表数据列表 </el-divider>
|
||||
|
||||
<!-- <p><el-tag style="border: 1 solid var(--el-border-color)">以下默认页面左右布局,左边布局显示树形列表,右边布局上下结构显示主子表数据列表</el-tag></p> -->
|
||||
<el-tabs v-model="activeName" class="demo-tabs">
|
||||
<el-tab-pane label="页面左边树" name="1">
|
||||
<el-tab-pane label="页面左(树列表)" name="1">
|
||||
<el-row :gutter="10">
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="树库定位器" prop="configId2">
|
||||
<el-form-item label="树 - 库定位器" prop="configId2">
|
||||
<el-select v-model="state.ruleForm.configId2" placeholder="库名" filterable @change="dbChanged2()" class="w100">
|
||||
<el-option v-for="item in state.dbData" :key="item.configId" :label="item.configId" :value="item.configId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<!-- <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="Name字段" prop="treeName" :rules="[{ required: true, message: '请选择树控件Name字段', trigger: 'blur' }]">
|
||||
<el-select v-model="state.ruleForm.treeName" @change="treeNameChanged" value-key="value" filterable clearable class="w100">
|
||||
<el-option v-for="item in state.columnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col> -->
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="左边树表" prop="leftTab">
|
||||
<el-form-item label="树表名称">
|
||||
<template v-slot:label>
|
||||
<div>
|
||||
左边树表
|
||||
树表名称
|
||||
<el-tooltip raw-content content="若找不到在前端生成的实体/表,同上,如表有下划线_则因实体去掉划线取不到字段。" placement="top">
|
||||
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
@ -240,14 +243,14 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="左边树关联字段" prop="leftKey">
|
||||
<el-form-item label="树关联字段">
|
||||
<el-select v-model="state.ruleForm.leftKey" @change="leftKeyChanged" value-key="value" filterable clearable class="w100">
|
||||
<el-option v-for="item in state.lcolumnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="关联主表字段" prop="bottomKey">
|
||||
<el-form-item label="关联主表字段">
|
||||
<template v-slot:label>
|
||||
<div>
|
||||
关联主表字段
|
||||
@ -263,7 +266,7 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="左边树Name字段" prop="leftName">
|
||||
<el-form-item label="树显示名称">
|
||||
<el-select v-model="state.ruleForm.leftName" @change="leftNameChanged" value-key="value" filterable clearable class="w100">
|
||||
<el-option v-for="item in state.lcolumnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
|
||||
</el-select>
|
||||
@ -271,26 +274,26 @@
|
||||
</el-col>
|
||||
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="模板" prop="template">
|
||||
<el-form-item label="模板">
|
||||
<el-input v-model="state.ruleForm.template" clearable placeholder="请输入" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="右区域下框" name="2">
|
||||
<el-tab-pane label="页面右(主子表)" name="2">
|
||||
<el-row :gutter="10">
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="右区域下框库定位器" prop="configId3">
|
||||
<el-form-item label="子表 - 库定位器" prop="configId3">
|
||||
<el-select v-model="state.ruleForm.configId3" placeholder="库名" filterable @change="dbChanged3()" class="w100">
|
||||
<el-option v-for="item in state.dbData" :key="item.configId" :label="item.configId" :value="item.configId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="下表名称" prop="bottomTab">
|
||||
<el-form-item label="子表名称" prop="bottomTab">
|
||||
<template v-slot:label>
|
||||
<div>
|
||||
下框关联表名称
|
||||
子表名称
|
||||
<el-tooltip raw-content content="若找不到在前端生成的实体/表,同上,如表有下划线_则因实体去掉划线取不到字段。" placement="top">
|
||||
<el-icon size="16" style="margin-right: 3px; display: inline; vertical-align: middle"><ele-QuestionFilled /></el-icon>
|
||||
</el-tooltip>
|
||||
@ -302,7 +305,7 @@
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
|
||||
<el-form-item label="下框表关联字段" prop="bottomKey">
|
||||
<el-form-item label="子表关联字段" prop="bottomKey">
|
||||
<el-select v-model="state.ruleForm.bottomKey" @change="bottomKeyChanged" value-key="value" filterable clearable class="w100">
|
||||
<el-option v-for="item in state.bcolumnData" :key="item.columnName" :label="item.columnName + ' ( ' + item.columnName + ' ) [' + item.columnComment + ']'" :value="item" />
|
||||
</el-select>
|
||||
@ -330,7 +333,7 @@
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="选择模板" name="template" style="height: 600px">
|
||||
<el-tab-pane label="选择模板" name="template" style="height: 700px">
|
||||
<el-table ref="templateTableRef" :data="templateTableData" @selection-change="handleSelectionChange" style="width: 100%">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column property="name" label="模板文件名" width="280" />
|
||||
|
||||
Loading…
Reference in New Issue
Block a user