模型限制: 系统配置全局开放/禁止 + 用户级限制 + 网关拦截
- User 新增 allowed_models/denied_models(用户级模型限制) - 系统配置 model_allowlist/model_denylist 全局策略, 保存即时失效网关缓存 - 网关 checkModelAllowed: 用户级 > 全局(禁止命中→403, 白名单非空→仅白名单) - 三个协议处理器均校验, 错误按客户端协议格式返回 - 配置页"模型限制"卡片(全局允许/禁止多选); 用户编辑支持允许/禁止模型 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -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})
|
||||
}
|
||||
|
||||
@@ -8,18 +8,20 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/openteam/server/internal/app"
|
||||
"github.com/openteam/server/internal/api/middleware"
|
||||
"github.com/openteam/server/internal/app"
|
||||
"github.com/openteam/server/internal/pkg/resp"
|
||||
"github.com/openteam/server/internal/proxy"
|
||||
"github.com/openteam/server/internal/store"
|
||||
)
|
||||
|
||||
// Handler 聚合所有管理 API。
|
||||
type Handler struct {
|
||||
a *app.App
|
||||
a *app.App
|
||||
gw *proxy.Gateway
|
||||
}
|
||||
|
||||
func NewHandler(a *app.App) *Handler { return &Handler{a: a} }
|
||||
func NewHandler(a *app.App, gw *proxy.Gateway) *Handler { return &Handler{a: a, gw: gw} }
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 认证
|
||||
@@ -219,6 +221,8 @@ func (h *Handler) publicUser(u *store.User) gin.H {
|
||||
"role": u.Role,
|
||||
"balance": u.Balance,
|
||||
"status": u.Status,
|
||||
"allowed_models": u.AllowedModels,
|
||||
"denied_models": u.DeniedModels,
|
||||
"created_at": u.CreatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func NewRouter(a *app.App, gw *proxy.Gateway) *gin.Engine {
|
||||
r := gin.New()
|
||||
r.Use(gin.Logger(), gin.Recovery(), middleware.CORS())
|
||||
|
||||
h := NewHandler(a)
|
||||
h := NewHandler(a, gw)
|
||||
|
||||
// --- 代理端点(对外)---
|
||||
proxyGroup := r.Group("/v1")
|
||||
|
||||
Reference in New Issue
Block a user