feat(imLoginFailureLog): 用户登录密码错误次数锁定与解锁能力(管理端)

- 安全策略登录限频由 JSON 文本改为结构化表单(次数/锁定分钟/窗口分钟),编辑校验同步扩展
- 失败日志新增解锁入口:/imLoginFailureLog/unlock 经 internal 通道调用 im-server 释放锁定
- 失败日志模型补充 accountHash 字段,解锁按钮按 risk_action=account_locked 展示
- 租户业务库初始化模板补充 im_login_lockouts 等表;新增解锁按钮菜单权限 SQL
This commit is contained in:
Austin
2026-09-20 17:04:19 +08:00
parent fd4ff85191
commit 8675fe333d
13 changed files with 238 additions and 19 deletions
@@ -5,6 +5,7 @@ import (
"fmt"
"hotgo/internal/consts"
"hotgo/internal/library/contexts"
"hotgo/internal/library/imadmin"
"hotgo/internal/library/imkafka"
"hotgo/internal/model/input/form"
"hotgo/internal/model/input/sysin"
@@ -15,6 +16,7 @@ import (
"strconv"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gctx"
)
@@ -128,6 +130,26 @@ func (s *sSysImLoginFailureLog) AddBlacklist(ctx context.Context, in *sysin.ImLo
})
}
func (s *sSysImLoginFailureLog) Unlock(ctx context.Context, in *sysin.ImLoginFailureUnlockInp) error {
if err := in.Filter(ctx); err != nil {
return err
}
tenant, err := resolveImAdminTenant(ctx, in.TenantId)
if err != nil {
return err
}
path := "/internal/admin-query/tenants/" + url.PathEscape(tenant.Code) + "/login-lockouts/release"
var out struct {
AccountHash string `json:"account_hash"`
Status string `json:"status"`
}
if err = imadmin.DefaultClient(ctx).InternalPost(ctx, path, map[string]string{"account_hash": in.AccountHash}, &out); err != nil {
return err
}
g.Log().Infof(ctx, "登录锁定已解锁 tenantId:%d accountHash:%s adminId:%d status:%s", tenant.Id, in.AccountHash, contexts.GetUserId(ctx), out.Status)
return nil
}
func (s *sSysImLoginFailureLog) BanUser(ctx context.Context, in *sysin.ImLoginFailureBanUserInp) (*sysin.ImUserCommandModel, error) {
if err := in.Filter(ctx); err != nil {
return nil, err