fix(security-policy): 修复策略保存时租户行更新时间与事件投递阻塞问题
调整策略保存时的租户表更新逻辑,显式赋值updated_at避免自动填充干扰 修改策略变更事件投递逻辑,失败时仅告警审计不阻塞主流程 新增租户无策略时加载模板初始化配置的逻辑,提升默认策略灵活性
This commit is contained in:
@@ -179,9 +179,10 @@ func (s *sSysImSecurityPolicy) Save(ctx context.Context, in *sysin.ImSecurityPol
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tenantID > 0 {
|
if tenantID > 0 {
|
||||||
// 上游已将商户配置并入 im_tenant 表,此处同步冗余开关与策略版本(商户行必然存在,无需补建)
|
// 上游已将商户配置并入 im_tenant 表,此处同步冗余开关与策略版本。
|
||||||
|
// updated_at 显式自赋值:抑制 gf 自动填充与 ON UPDATE CURRENT_TIMESTAMP,策略保存不 touch 商户行的更新人/时间
|
||||||
if _, cfgErr := tx.Model(dao.ImTenant.Table()).Safe().Ctx(ctx).Where(tc.Id, tenantID).
|
if _, cfgErr := tx.Model(dao.ImTenant.Table()).Safe().Ctx(ctx).Where(tc.Id, tenantID).
|
||||||
Data(g.Map{tc.SecurityPolicyVersion: version, tc.GlobalFriendEnabled: in.GlobalFriendEnabled, tc.MessageCurfewEnabled: in.MessageCurfewEnabled, tc.UpdatedAt: now, tc.UpdatedBy: operator}).Update(); cfgErr != nil {
|
Data(g.Map{tc.SecurityPolicyVersion: version, tc.GlobalFriendEnabled: in.GlobalFriendEnabled, tc.MessageCurfewEnabled: in.MessageCurfewEnabled, tc.UpdatedAt: gdb.Raw("updated_at")}).Update(); cfgErr != nil {
|
||||||
return cfgErr
|
return cfgErr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -191,9 +192,11 @@ func (s *sSysImSecurityPolicy) Save(ctx context.Context, in *sysin.ImSecurityPol
|
|||||||
return 0, gerror.Wrap(err, "保存安全策略失败")
|
return 0, gerror.Wrap(err, "保存安全策略失败")
|
||||||
}
|
}
|
||||||
_ = writeImAdminAudit(ctx, tenantID, "im_security_policy_save", "im_security_policy", id, "success", g.Map{"version": version, "global_friend_enabled": in.GlobalFriendEnabled, "message_curfew_enabled": in.MessageCurfewEnabled})
|
_ = writeImAdminAudit(ctx, tenantID, "im_security_policy_save", "im_security_policy", id, "success", g.Map{"version": version, "global_friend_enabled": in.GlobalFriendEnabled, "message_curfew_enabled": in.MessageCurfewEnabled})
|
||||||
// 保存即生效:投递策略变更事件,IM 端消费后失效策略缓存并回源拉取新配置
|
// 保存即生效:投递策略变更事件,IM 端消费后失效策略缓存并回源拉取新配置。
|
||||||
if err = publishImPolicyEvent(ctx, tenantID, tenantCode, "security.policy.updated", "security_policy", version); err != nil {
|
// 事件已持久化到 im_admin_outbox,立即投递失败仅告警+审计、由 outbox 重试续投,不阻塞已生效的保存结果
|
||||||
return id, err
|
if pubErr := publishImPolicyEvent(ctx, tenantID, tenantCode, "security.policy.updated", "security_policy", version); pubErr != nil {
|
||||||
|
g.Log().Warningf(ctx, "IM策略事件投递失败(outbox将重试): tenant=%d version=%d err=%v", tenantID, version, pubErr)
|
||||||
|
_ = writeImAdminAudit(ctx, tenantID, "im_policy_event_publish", "im_security_policy", id, "failed", g.Map{"error": pubErr.Error(), "version": version})
|
||||||
}
|
}
|
||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
@@ -305,10 +308,31 @@ func (s *sSysImSecurityPolicy) SaveLoginLockoutConfig(ctx context.Context, in *s
|
|||||||
return gerror.Wrap(err, "保存登录失败策略配置失败")
|
return gerror.Wrap(err, "保存登录失败策略配置失败")
|
||||||
}
|
}
|
||||||
_ = writeImAdminAudit(ctx, tenantID, "im_security_policy_login_lockout_save", "im_security_policy", policyID, "success", g.Map{"enabled": in.Enabled, "password_max_attempts": in.PasswordMaxAttempts, "lock_minutes": in.LockMinutes, "window_minutes": in.WindowMinutes})
|
_ = writeImAdminAudit(ctx, tenantID, "im_security_policy_login_lockout_save", "im_security_policy", policyID, "success", g.Map{"enabled": in.Enabled, "password_max_attempts": in.PasswordMaxAttempts, "lock_minutes": in.LockMinutes, "window_minutes": in.WindowMinutes})
|
||||||
return publishImPolicyEvent(ctx, tenantID, tenantCode, "security.policy.updated", "security_policy", version)
|
if pubErr := publishImPolicyEvent(ctx, tenantID, tenantCode, "security.policy.updated", "security_policy", version); pubErr != nil {
|
||||||
|
g.Log().Warningf(ctx, "IM策略事件投递失败(outbox将重试): tenant=%d version=%d err=%v", tenantID, version, pubErr)
|
||||||
|
_ = writeImAdminAudit(ctx, tenantID, "im_policy_event_publish", "im_security_policy", policyID, "failed", g.Map{"error": pubErr.Error(), "version": version})
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
// 租户尚无策略:保存默认策略,保存即生效并投递策略变更事件
|
// 租户尚无策略:按模板复制初始策略(模板未初始化时退回内置默认值),仅覆盖登录失败配置,保存即生效并投递策略变更事件
|
||||||
id, saveErr := s.Save(ctx, &sysin.ImSecurityPolicySaveInp{TenantId: tenantID, PolicyName: "默认安全策略", LoginRateLimit: gjson.New(value), GlobalFriendEnabled: 1, MessageCurfewEnabled: 0})
|
saveInp := &sysin.ImSecurityPolicySaveInp{TenantId: tenantID, PolicyName: "默认安全策略", LoginRateLimit: gjson.New(value), GlobalFriendEnabled: 1, MessageCurfewEnabled: 0}
|
||||||
|
tpl, tplErr := loadPolicyTemplateRow(imtenant.RegistryDB().Model(imPolicyTemplateTable).Safe().Ctx(ctx))
|
||||||
|
if tplErr != nil {
|
||||||
|
return gerror.Wrap(tplErr, "读取安全策略模板失败")
|
||||||
|
}
|
||||||
|
if tpl != nil {
|
||||||
|
saveInp.PolicyName = tpl["policy_name"].String()
|
||||||
|
saveInp.PasswordPolicy = gjson.New(tpl["password_policy"].String())
|
||||||
|
saveInp.SensitiveWordPolicy = gjson.New(tpl["sensitive_word_policy"].String())
|
||||||
|
saveInp.FileReviewPolicy = gjson.New(tpl["file_review_policy"].String())
|
||||||
|
saveInp.RealnamePolicy = gjson.New(tpl["realname_policy"].String())
|
||||||
|
saveInp.RiskChallengePolicy = gjson.New(tpl["risk_challenge_policy"].String())
|
||||||
|
saveInp.GlobalFriendEnabled = tpl["global_friend_enabled"].Int()
|
||||||
|
saveInp.FriendDisabledPolicy = gjson.New(tpl["friend_disabled_policy"].String())
|
||||||
|
saveInp.MessageCurfewEnabled = tpl["message_curfew_enabled"].Int()
|
||||||
|
saveInp.CurfewRules = templateCurfewRules(tpl)
|
||||||
|
}
|
||||||
|
id, saveErr := s.Save(ctx, saveInp)
|
||||||
if saveErr != nil {
|
if saveErr != nil {
|
||||||
return saveErr
|
return saveErr
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user