😎同步升级、代码优化

This commit is contained in:
zuohuaijun 2024-06-25 02:33:24 +08:00
parent 22f1e1bba7
commit 716884da90
12 changed files with 109 additions and 50 deletions

View File

@ -56,10 +56,11 @@ public class AppAuthService : IDynamicApiController, ITransient
[DisplayName("账号密码登录")]
public virtual async Task<LoginOutput> Login([Required] LoginInput input)
{
// 判断密码错误次数默认5次缓存30分钟
var keyErrorPasswordCount = $"{CacheConst.KeyErrorPasswordCount}{input.Account}";
var errorPasswordCount = _sysCacheService.Get<int>(keyErrorPasswordCount);
if (errorPasswordCount >= 5)
// 判断密码错误次数缓存30分钟
var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{input.Account}";
var passwordErrorTimes = _sysCacheService.Get<int>(keyPasswordErrorTimes);
var passwdMaxErrorTimes = await _sysConfigService.GetConfigValue<int>(CommonConst.SysPasswdMaxErrorTimes);
if (passwordErrorTimes >= passwdMaxErrorTimes)
throw Oops.Oh(ErrorCodeEnum.D1027);
// 是否开启验证码
@ -93,10 +94,10 @@ public class AppAuthService : IDynamicApiController, ITransient
throw Oops.Oh(ErrorCodeEnum.D0010);
}
VerifyPassword(input, keyErrorPasswordCount, errorPasswordCount, user);
VerifyPassword(input, keyPasswordErrorTimes, passwordErrorTimes, user);
// 登录成功则清空密码错误次数
_sysCacheService.Remove(keyErrorPasswordCount);
_sysCacheService.Remove(keyPasswordErrorTimes);
return await CreateToken(user);
}

View File

@ -37,7 +37,7 @@
<PackageReference Include="SqlSugarCore" Version="5.1.4.159" />
<PackageReference Include="SSH.NET" Version="2024.0.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.4.1" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1031" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1032" />
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup>

View File

@ -54,7 +54,7 @@ public class CacheConst
/// <summary>
/// 密码错误次数缓存
/// </summary>
public const string KeyErrorPasswordCount = "sys_errorPasswordCount:";
public const string KeyPasswordErrorTimes = "sys_password_error_times:";
/// <summary>
/// 租户缓存

View File

@ -22,6 +22,11 @@ public class CommonConst
/// </summary>
public const string SysPassword = "sys_password";
/// <summary>
/// 密码最大错误次数
/// </summary>
public const string SysPasswdMaxErrorTimes = "sys_passwd_max_error_times";
/// <summary>
/// 登录二次验证
/// </summary>

View File

@ -0,0 +1,41 @@
// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using System.Net;
namespace Admin.NET.Core;
/// <summary>
/// HttpContext拓展
/// </summary>
[SuppressSniffer]
public static partial class HttpContextExtension
{
/// <summary>
/// 获取客户端真实 IP 地址
/// </summary>
/// <returns>bool</returns>
public static string GetRemoteIp(this HttpContext httpContext)
{
var ip = string.Empty;
try
{
// 从 X-Forwarded-For 头获取 IP
ip = httpContext.Request.Headers["X-Forwarded-For"];
if (string.IsNullOrEmpty(ip))
{
ip = httpContext.GetRemoteIpAddressToIPv4();
}
// 验证 IP 地址有效性
if (!IPAddress.TryParse(ip, out _))
{
ip = null;
}
}
catch { }
return ip;
}
}

View File

@ -21,23 +21,24 @@ public class SysConfigSeedData : ISqlSugarEntitySeedData<SysConfig>
{
new SysConfig{ Id=1300000000101, Name="演示环境", Code="sys_demo", Value="False", SysFlag=YesNoEnum.Y, Remark="演示环境", OrderNo=10, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000111, Name="默认密码", Code="sys_password", Value="123456", SysFlag=YesNoEnum.Y, Remark="默认密码", OrderNo=20, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000121, Name="记录操作日志", Code="sys_oplog", Value="True", SysFlag=YesNoEnum.Y, Remark="是否记录操作日志", OrderNo=30, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000131, Name="开启单设备登录", Code="sys_single_login", Value="False", SysFlag=YesNoEnum.Y, Remark="是否开启单设备登录", OrderNo=40, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000141, Name="开启登录二次验证", Code="sys_second_ver", Value="False", SysFlag=YesNoEnum.Y, Remark="是否开启登录二次验证", OrderNo=50, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000151, Name="开启图形验证码", Code="sys_captcha", Value="True", SysFlag=YesNoEnum.Y, Remark="是否开启图形验证码", OrderNo=60, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000161, Name="Token过期时间", Code="sys_token_expire", Value="10080", SysFlag=YesNoEnum.Y, Remark="Token过期时间分钟", OrderNo=70, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000171, Name="刷新Token过期时间", Code="sys_refresh_token_expire", Value="20160", SysFlag=YesNoEnum.Y, Remark="刷新Token过期时间分钟一般 refresh_token 的有效时间 > 2 * access_token 的有效时间)", OrderNo=80, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000181, Name="发送异常日志邮件", Code="sys_error_mail", Value="True", SysFlag=YesNoEnum.Y, Remark="是否发送异常日志邮件", OrderNo=90, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000191, Name="开启域登录验证", Code="sys_domain_login", Value="False", SysFlag=YesNoEnum.Y, Remark="是否开启域登录验证", OrderNo=100, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000192, Name="开启数据校验日志", Code="sys_validation_log", Value="True", SysFlag=YesNoEnum.Y, Remark="是否数据校验日志", OrderNo=110, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000211, Name="系统主标题", Code="sys_web_title", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="系统主标题", OrderNo=110, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000221, Name="系统副标题", Code="sys_web_viceTitle", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="系统副标题", OrderNo=120, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000231, Name="系统描述", Code="sys_web_viceDesc", Value="站在巨人肩膀上的 .NET 通用权限开发框架", SysFlag=YesNoEnum.Y, Remark="系统描述", OrderNo=130, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000241, Name="水印内容", Code="sys_web_watermark", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="水印内容", OrderNo=140, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000251, Name="版权说明", Code="sys_web_copyright", Value="Copyright © 2021-present Admin.NET All rights reserved.", SysFlag=YesNoEnum.Y, Remark="版权说明", OrderNo=150, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000261, Name="系统图标", Code="sys_web_logo", Value="/Upload/logo.png", SysFlag=YesNoEnum.Y, Remark="系统图标", OrderNo=160, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000271, Name="ICP备案号", Code="sys_web_icp", Value="省ICP备12345678号", SysFlag=YesNoEnum.Y, Remark="ICP备案号", OrderNo=170, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000281, Name="ICP地址", Code="sys_web_icpUrl", Value="https://beian.miit.gov.cn", SysFlag=YesNoEnum.Y, Remark="ICP地址", OrderNo=180, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000121, Name="密码最大错误次数", Code="sys_passwd_max_error_times", Value="5", SysFlag=YesNoEnum.Y, Remark="允许密码最大输入错误次数", OrderNo=30, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000131, Name="记录操作日志", Code="sys_oplog", Value="True", SysFlag=YesNoEnum.Y, Remark="是否记录操作日志", OrderNo=40, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000141, Name="开启单设备登录", Code="sys_single_login", Value="False", SysFlag=YesNoEnum.Y, Remark="是否开启单设备登录", OrderNo=50, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000151, Name="开启登录二次验证", Code="sys_second_ver", Value="False", SysFlag=YesNoEnum.Y, Remark="是否开启登录二次验证", OrderNo=60, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000161, Name="开启图形验证码", Code="sys_captcha", Value="True", SysFlag=YesNoEnum.Y, Remark="是否开启图形验证码", OrderNo=+0, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000171, Name="Token过期时间", Code="sys_token_expire", Value="10080", SysFlag=YesNoEnum.Y, Remark="Token过期时间分钟", OrderNo=80, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000181, Name="刷新Token过期时间", Code="sys_refresh_token_expire", Value="20160", SysFlag=YesNoEnum.Y, Remark="刷新Token过期时间分钟一般 refresh_token 的有效时间 > 2 * access_token 的有效时间)", OrderNo=90, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000191, Name="发送异常日志邮件", Code="sys_error_mail", Value="True", SysFlag=YesNoEnum.Y, Remark="是否发送异常日志邮件", OrderNo=100, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000201, Name="开启域登录验证", Code="sys_domain_login", Value="False", SysFlag=YesNoEnum.Y, Remark="是否开启域登录验证", OrderNo=110, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000211, Name="开启数据校验日志", Code="sys_validation_log", Value="True", SysFlag=YesNoEnum.Y, Remark="是否数据校验日志", OrderNo=120, GroupCode="Default", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000221, Name="系统主标题", Code="sys_web_title", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="系统主标题", OrderNo=130, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000231, Name="系统副标题", Code="sys_web_viceTitle", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="系统副标题", OrderNo=140, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000241, Name="系统描述", Code="sys_web_viceDesc", Value="站在巨人肩膀上的 .NET 通用权限开发框架", SysFlag=YesNoEnum.Y, Remark="系统描述", OrderNo=150, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000251, Name="水印内容", Code="sys_web_watermark", Value="Admin.NET", SysFlag=YesNoEnum.Y, Remark="水印内容", OrderNo=160, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000261, Name="版权说明", Code="sys_web_copyright", Value="Copyright © 2021-present Admin.NET All rights reserved.", SysFlag=YesNoEnum.Y, Remark="版权说明", OrderNo=170, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000271, Name="系统图标", Code="sys_web_logo", Value="/Upload/logo.png", SysFlag=YesNoEnum.Y, Remark="系统图标", OrderNo=180, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000281, Name="ICP备案号", Code="sys_web_icp", Value="省ICP备12345678号", SysFlag=YesNoEnum.Y, Remark="ICP备案号", OrderNo=190, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
new SysConfig{ Id=1300000000291, Name="ICP地址", Code="sys_web_icpUrl", Value="https://beian.miit.gov.cn", SysFlag=YesNoEnum.Y, Remark="ICP地址", OrderNo=200, GroupCode="WebConfig", CreateTime=DateTime.Parse("2022-02-10 00:00:00") },
};
}
}

View File

@ -62,10 +62,11 @@ public class SysAuthService : IDynamicApiController, ITransient
//// 可以根据域名获取具体租户
//var host = _httpContextAccessor.HttpContext.Request.Host;
// 判断密码错误次数默认5次缓存30分钟
var keyErrorPasswordCount = $"{CacheConst.KeyErrorPasswordCount}{input.Account}";
var errorPasswordCount = _sysCacheService.Get<int>(keyErrorPasswordCount);
if (errorPasswordCount >= 5)
// 判断密码错误次数缓存30分钟
var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{input.Account}";
var passwordErrorTimes = _sysCacheService.Get<int>(keyPasswordErrorTimes);
var passwdMaxErrorTimes = await _sysConfigService.GetConfigValue<int>(CommonConst.SysPasswdMaxErrorTimes);
if (passwordErrorTimes >= passwdMaxErrorTimes)
throw Oops.Oh(ErrorCodeEnum.D1027);
// 是否开启验证码
@ -105,19 +106,19 @@ public class SysAuthService : IDynamicApiController, ITransient
var userLdap = await _sysUserLdap.GetFirstAsync(u => u.UserId == user.Id && u.TenantId == tenant.Id);
if (userLdap == null)
{
VerifyPassword(input, keyErrorPasswordCount, errorPasswordCount, user);
VerifyPassword(input, keyPasswordErrorTimes, passwordErrorTimes, user);
}
else if (!await _sysLdapService.AuthAccount(tenant.Id, userLdap.Account, input.Password))
{
_sysCacheService.Set(keyErrorPasswordCount, ++errorPasswordCount, TimeSpan.FromMinutes(30));
_sysCacheService.Set(keyPasswordErrorTimes, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
throw Oops.Oh(ErrorCodeEnum.D1000);
}
}
else
VerifyPassword(input, keyErrorPasswordCount, errorPasswordCount, user);
VerifyPassword(input, keyPasswordErrorTimes, passwordErrorTimes, user);
// 登录成功则清空密码错误次数
_sysCacheService.Remove(keyErrorPasswordCount);
_sysCacheService.Remove(keyPasswordErrorTimes);
return await CreateToken(user);
}
@ -126,16 +127,16 @@ public class SysAuthService : IDynamicApiController, ITransient
/// 验证用户密码
/// </summary>
/// <param name="input"></param>
/// <param name="keyErrorPasswordCount"></param>
/// <param name="errorPasswordCount"></param>
/// <param name="keyPasswordErrorTims"></param>
/// <param name="passwordErrorTimes"></param>
/// <param name="user"></param>
private void VerifyPassword(LoginInput input, string keyErrorPasswordCount, int errorPasswordCount, SysUser user)
private void VerifyPassword(LoginInput input, string keyPasswordErrorTims, int passwordErrorTimes, SysUser user)
{
if (CryptogramUtil.CryptoType == CryptogramEnum.MD5.ToString())
{
if (!user.Password.Equals(MD5Encryption.Encrypt(input.Password)))
{
_sysCacheService.Set(keyErrorPasswordCount, ++errorPasswordCount, TimeSpan.FromMinutes(30));
_sysCacheService.Set(keyPasswordErrorTims, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
throw Oops.Oh(ErrorCodeEnum.D1000);
}
}
@ -143,7 +144,7 @@ public class SysAuthService : IDynamicApiController, ITransient
{
if (!CryptogramUtil.Decrypt(user.Password).Equals(input.Password))
{
_sysCacheService.Set(keyErrorPasswordCount, ++errorPasswordCount, TimeSpan.FromMinutes(30));
_sysCacheService.Set(keyPasswordErrorTims, ++passwordErrorTimes, TimeSpan.FromMinutes(30));
throw Oops.Oh(ErrorCodeEnum.D1000);
}
}

View File

@ -14,12 +14,18 @@ public class SysConfigService : IDynamicApiController, ITransient
{
private readonly SysCacheService _sysCacheService;
private readonly SqlSugarRepository<SysConfig> _sysConfigRep;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly UserManager _userManager;
public SysConfigService(SysCacheService sysCacheService,
SqlSugarRepository<SysConfig> sysConfigRep)
SqlSugarRepository<SysConfig> sysConfigRep,
IHttpContextAccessor httpContextAccessor,
UserManager userManager)
{
_sysCacheService = sysCacheService;
_sysConfigRep = sysConfigRep;
_httpContextAccessor = httpContextAccessor;
_userManager = userManager;
}
/// <summary>
@ -245,6 +251,10 @@ public class SysConfigService : IDynamicApiController, ITransient
var sysCopyright = await GetConfigValue<string>("sys_web_copyright");
var sysIcp = await GetConfigValue<string>("sys_web_icp");
var sysIcpUrl = await GetConfigValue<string>("sys_web_icpUrl");
//var ip = _httpContextAccessor.HttpContext.GetRemoteIp();
//var watermark = $"{sysWatermark}-{DateTime.Now}-{ip}-{_userManager.RealName}";
return new
{
SysLogo = sysLogo,

View File

@ -318,8 +318,8 @@ public class SysUserService : IDynamicApiController, ITransient
await _sysUserRep.AsUpdateable(user).UpdateColumns(u => u.Password).ExecuteCommandAsync();
// 清空密码错误次数
var keyErrorPasswordCount = $"{CacheConst.KeyErrorPasswordCount}{user.Account}";
_sysCacheService.Remove(keyErrorPasswordCount);
var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{user.Account}";
_sysCacheService.Remove(keyPasswordErrorTimes);
return password;
}
@ -335,8 +335,8 @@ public class SysUserService : IDynamicApiController, ITransient
var user = await _sysUserRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D0009);
// 清空密码错误次数
var keyErrorPasswordCount = $"{CacheConst.KeyErrorPasswordCount}{user.Account}";
_sysCacheService.Remove(keyErrorPasswordCount);
var keyPasswordErrorTimes = $"{CacheConst.KeyPasswordErrorTimes}{user.Account}";
_sysCacheService.Remove(keyPasswordErrorTimes);
}
/// <summary>

View File

@ -24,7 +24,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Rezero.Api" Version="1.7.2" />
<PackageReference Include="Rezero.Api" Version="1.7.4" />
</ItemGroup>
<ItemGroup>

View File

@ -2,7 +2,7 @@
"name": "admin.net.pro",
"type": "module",
"version": "2.4.33",
"lastBuildTime": "2024.6.21",
"lastBuildTime": "2024.6.25",
"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",
"author": "zuohuaijun",
"license": "MIT",
@ -72,8 +72,8 @@
"@types/node": "^20.14.8",
"@types/nprogress": "^0.2.3",
"@types/sortablejs": "^1.15.8",
"@typescript-eslint/eslint-plugin": "^7.13.1",
"@typescript-eslint/parser": "^7.13.1",
"@typescript-eslint/eslint-plugin": "^7.14.1",
"@typescript-eslint/parser": "^7.14.1",
"@vitejs/plugin-vue": "^5.0.5",
"@vitejs/plugin-vue-jsx": "^4.0.0",
"@vue/compiler-sfc": "^3.4.30",

View File

@ -3,14 +3,14 @@ const setWatermark = (str: string) => {
const id = '1.23452384164.123412416';
if (document.getElementById(id) !== null) document.body.removeChild(<HTMLElement>document.getElementById(id));
const can = document.createElement('canvas');
can.width = 200;
can.height = 130;
can.width = 400;
can.height = 200;
const cans = <CanvasRenderingContext2D>can.getContext('2d');
cans.rotate((-20 * Math.PI) / 180);
cans.font = '12px Vedana';
cans.fillStyle = 'rgba(200, 200, 200, 0.30)';
cans.textBaseline = 'middle';
cans.fillText(str, can.width / 10, can.height / 2);
cans.fillText(str, can.width / 10, can.height, can.width);
const div = document.createElement('div');
div.id = id;
div.style.pointerEvents = 'none';