模型限制: 系统配置全局开放/禁止 + 用户级限制 + 网关拦截

- User 新增 allowed_models/denied_models(用户级模型限制)
- 系统配置 model_allowlist/model_denylist 全局策略, 保存即时失效网关缓存
- 网关 checkModelAllowed: 用户级 > 全局(禁止命中→403, 白名单非空→仅白名单)
- 三个协议处理器均校验, 错误按客户端协议格式返回
- 配置页"模型限制"卡片(全局允许/禁止多选); 用户编辑支持允许/禁止模型

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Sakurasan
2026-08-16 01:34:12 +08:00
co-authored by Claude
parent 866690b7ce
commit b365779188
9 changed files with 240 additions and 28 deletions
+20 -5
View File
@@ -48,11 +48,13 @@ func (h *Handler) AdminPatchUser(c *gin.Context) {
return
}
var req struct {
Username *string `json:"username"`
Email *string `json:"email"`
Password *string `json:"password"`
Role *string `json:"role"`
Status *string `json:"status"`
Username *string `json:"username"`
Email *string `json:"email"`
Password *string `json:"password"`
Role *string `json:"role"`
Status *string `json:"status"`
AllowedModels *[]string `json:"allowed_models"`
DeniedModels *[]string `json:"denied_models"`
}
if err := c.ShouldBindJSON(&req); err != nil {
resp.Fail(c, http.StatusBadRequest, "invalid input")
@@ -113,6 +115,15 @@ func (h *Handler) AdminPatchUser(c *gin.Context) {
}
updates["status"] = *req.Status
}
// 模型限制(jsonb):手动序列化
if req.AllowedModels != nil {
raw, _ := json.Marshal(*req.AllowedModels)
updates["allowed_models"] = string(raw)
}
if req.DeniedModels != nil {
raw, _ := json.Marshal(*req.DeniedModels)
updates["denied_models"] = string(raw)
}
if len(updates) == 0 {
resp.OK(c, gin.H{"ok": true})
return
@@ -211,5 +222,9 @@ func (h *Handler) AdminPutConfig(c *gin.Context) {
resp.Fail(c, http.StatusInternalServerError, "failed to save config")
return
}
// 模型限制等策略可能变化,立即失效缓存
if h.gw != nil {
h.gw.ResetModelPolicy()
}
resp.OK(c, gin.H{"ok": true})
}