fix(setting):移除安全配置中的无用配置

This commit is contained in:
qian committed 2026-09-01 21:34:45 +08:00
1 parent df78724773
commit e800cd4b05
5 files changed
+27 -59

No files matched your search

+5 -4
View File
@@ -84,12 +84,13 @@ func (s *sAdmin) Login(ctx context.Context, req *v1.AdminLoginReq) (*v1.AdminLog
if !crypto.VerifyPassword(req.Password, user.PasswordHash) {
_ = common.RecordLoginHistory(ctx, "admin", user.Id, 0, "password", ipAddress, ua, deviceFP, false, "密码错误")
// 原子递增失败次数
// 原子递增失败次数;锁定阈值与时长取自安全配置(sys_options)
updateData := do.SysAdminUsers{FailedAttempts: gdb.Raw("failed_attempts + 1")}
failedAttempts := user.FailedAttempts + 1
maxAttempts, lockoutMinutes := common.LoginLockoutPolicy(ctx)
if failedAttempts >= 5 {
lockedUntil := time.Now().Add(30 * time.Minute)
if failedAttempts >= maxAttempts {
lockedUntil := time.Now().Add(time.Duration(lockoutMinutes) * time.Minute)
updateData.LockedUntil = gtime.NewFromTime(lockedUntil)
_, err := dao.SysAdminUsers.Ctx(ctx).
Where("id", user.Id).
@@ -98,7 +99,7 @@ func (s *sAdmin) Login(ctx context.Context, req *v1.AdminLoginReq) (*v1.AdminLog
g.Log().Errorf(ctx, "更新管理员账号锁定状态失败: %v", err)
}
return nil, common.NewBusinessError(consts.CodeAccountLocked,
"连续 5 次密码错误,账号已锁定 30 分钟")
fmt.Sprintf("连续 %d 次密码错误,账号已锁定 %d 分钟", maxAttempts, lockoutMinutes))
}
_, err := dao.SysAdminUsers.Ctx(ctx).
+14
View File
@@ -418,6 +418,20 @@ func RegenerateBackupCodes(ctx context.Context, userType string, userID int64, c
return plainCodes, nil
}
// LoginLockoutPolicy 返回登录锁定策略(安全配置 sys_options:login_max_attempts / login_lockout_minutes)。
// 未配置或非法值(<=0)时回退默认 5 次 / 30 分钟,管理后台与租户控制台共用同一策略。
func LoginLockoutPolicy(ctx context.Context) (maxAttempts, lockoutMinutes int) {
maxAttempts = Config().GetInt(ctx, "login_max_attempts")
if maxAttempts <= 0 {
maxAttempts = 5
}
lockoutMinutes = Config().GetInt(ctx, "login_lockout_minutes")
if lockoutMinutes <= 0 {
lockoutMinutes = 30
}
return maxAttempts, lockoutMinutes
}
// Is2FAEnabled checks if 2FA is enabled for a user.
func Is2FAEnabled(ctx context.Context, userType string, userID int64) (bool, error) {
if userType == "admin" {
+3 -10
View File
@@ -113,16 +113,11 @@ var Registry = []SettingDef{
Label: "启用 TLS", Description: "587/465 端口建议开启"},
// ── Security ──
{Key: "max_sessions_per_user", Type: SettingTypeInt, Default: "10", Category: "security",
Label: "租户用户最大会话数", Validation: "min:1,max:100"},
{Key: "admin_max_sessions", Type: SettingTypeInt, Default: "5", Category: "security",
Label: "管理员最大会话数", Validation: "min:1,max:50"},
// 会话数上限不入注册表:并发会话限制由配置文件 jwt.adminMaxSessions / jwt.tenantMaxSessions 管理
{Key: "login_max_attempts", Type: SettingTypeInt, Default: "5", Category: "security",
Label: "登录最大尝试次数", Validation: "min:1,max:30"},
Label: "登录最大尝试次数", Description: "连续密码错误达到该次数后锁定账号(管理后台 + 租户控制台)", Validation: "min:1,max:30"},
{Key: "login_lockout_minutes", Type: SettingTypeInt, Default: "30", Category: "security",
Label: "登录锁定时长(分钟)", Validation: "min:1,max:1440"},
{Key: "password_min_length", Type: SettingTypeInt, Default: "8", Category: "security",
Label: "密码最小长度", Validation: "min:6,max:32"},
Label: "登录锁定时长(分钟)", Description: "触发锁定后的持续时长(管理后台 + 租户控制台)", Validation: "min:1,max:1440"},
{Key: "turnstile_enabled", Type: SettingTypeBool, Default: "false", Category: "security",
Label: "启用 Turnstile 人机验证", IsPublic: true},
{Key: "turnstile_site_key", Type: SettingTypeString, Default: "", Category: "security",
@@ -131,8 +126,6 @@ var Registry = []SettingDef{
Label: "Turnstile Secret Key", Sensitive: true},
{Key: "captcha_expire_seconds", Type: SettingTypeInt, Default: "300", Category: "security",
Label: "验证码有效期(秒)", Validation: "min:60,max:600"},
{Key: "new_device_notification", Type: SettingTypeBool, Default: "true", Category: "security",
Label: "新设备登录通知"},
{Key: "register_forbidden_words", Type: SettingTypeString, Default: "admin,system,root,api,test,administrator,管理员,系统", Category: "security",
Label: "注册禁用词", Description: "组织名称、组织代码、用户名中包含这些词时禁止注册(不区分大小写),多个禁用词用英文逗号分隔"},
{Key: "sandbox_enabled", Type: SettingTypeBool, Default: "true", Category: "performance",
+5 -4
View File
@@ -412,12 +412,13 @@ func (s *sTenant) Login(ctx context.Context, req *v1.TenantLoginReq) (*v1.Tenant
if !crypto.VerifyPassword(req.Password, user.PasswordHash) {
_ = common.RecordLoginHistory(ctx, "tenant", user.Id, tenant.Id, "password", ipAddress, ua, deviceFP, false, "密码错误")
// 原子递增失败次数
// 原子递增失败次数;锁定阈值与时长取自安全配置(sys_options)
updateData := do.TntUsers{FailedAttempts: gdb.Raw("failed_attempts + 1")}
failedAttempts := user.FailedAttempts + 1
maxAttempts, lockoutMinutes := common.LoginLockoutPolicy(ctx)
if failedAttempts >= 5 {
lockedUntil := time.Now().Add(30 * time.Minute)
if failedAttempts >= maxAttempts {
lockedUntil := time.Now().Add(time.Duration(lockoutMinutes) * time.Minute)
updateData.LockedUntil = gtime.NewFromTime(lockedUntil)
_, err := dao.TntUsers.Ctx(ctx).
Where("id", user.Id).
@@ -426,7 +427,7 @@ func (s *sTenant) Login(ctx context.Context, req *v1.TenantLoginReq) (*v1.Tenant
g.Log().Errorf(ctx, "更新账号锁定状态失败: %v", err)
}
return nil, common.NewBusinessError(consts.CodeAccountLocked,
"连续 5 次密码错误,账号已锁定 30 分钟")
fmt.Sprintf("连续 %d 次密码错误,账号已锁定 %d 分钟", maxAttempts, lockoutMinutes))
}
_, err := dao.TntUsers.Ctx(ctx).
@@ -5,27 +5,6 @@ const values = useFormValues()
<template>
<div class="tab-content">
<!-- 会话管理 -->
<div class="section">
<div class="section-title">会话管理</div>
<div class="section-grid">
<AFormItem label="租户用户最大会话数">
<AInputNumber
:model-value="values['max_sessions_per_user'] as number"
@change="(v: number | undefined) => values['max_sessions_per_user'] = v ?? 10"
:min="1" :max="100" style="width: 100%"
/>
</AFormItem>
<AFormItem label="管理员最大会话数">
<AInputNumber
:model-value="values['admin_max_sessions'] as number"
@change="(v: number | undefined) => values['admin_max_sessions'] = v ?? 5"
:min="1" :max="50" style="width: 100%"
/>
</AFormItem>
</div>
</div>
<!-- 登录安全 -->
<div class="section">
<div class="section-title">登录安全</div>
@@ -47,20 +26,6 @@ const values = useFormValues()
</div>
</div>
<!-- 密码策略 -->
<div class="section">
<div class="section-title">密码策略</div>
<div class="section-grid">
<AFormItem label="密码最小长度">
<AInputNumber
:model-value="values['password_min_length'] as number"
@change="(v: number | undefined) => values['password_min_length'] = v ?? 8"
:min="6" :max="32" style="width: 100%"
/>
</AFormItem>
</div>
</div>
<!-- 验证码有效期 -->
<div class="section">
<div class="section-title">滑块验证码</div>
@@ -87,12 +52,6 @@ const values = useFormValues()
@change="(v: string | number | boolean) => values['turnstile_enabled'] = v"
/>
</AFormItem>
<AFormItem label="新设备登录通知">
<ASwitch
:model-value="!!values['new_device_notification']"
@change="(v: string | number | boolean) => values['new_device_notification'] = v"
/>
</AFormItem>
</div>
<div class="section-grid">
<AFormItem label="Site Key">