fix(access): 统一 API Key 模型权限与列表契约
将全局启用、用户组基线、API Key 专属或排除规则及 scope 按固定顺序求值,避免 Key 越过所属用户组权限,并让运行时候选与模型列表共用同一权限链。 新增 Key 级可分配模型与失效规则诊断接口、OpenAI 兼容 /v1/models 及 rich 列表迁移路径;前端权限弹窗改为按当前 Key 实时加载并支持清理失效规则。 验证:Go 全量测试与 go vet 通过;Web 22 个测试文件共 142 项通过;pnpm lint、pnpm openapi、pnpm build、Compose 配置、gofmt、ShellCheck 和 git diff --check 通过;独立 PostgreSQL 真实配置验收通过。
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
package httpapi
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sort"
|
||||
|
||||
"github.com/easyai/easyai-ai-gateway/apps/api/internal/auth"
|
||||
)
|
||||
|
||||
// listLegacyPlayableModels godoc
|
||||
// @Summary 列出可调用平台模型(已弃用)
|
||||
// @Description 兼容期 rich 平台来源明细;新客户端应改用 /api/v1/platform-models,OpenAI 客户端使用 /v1/models。
|
||||
// @Tags playground
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Deprecated
|
||||
// @Success 200 {object} PlatformModelListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /api/v1/models [get]
|
||||
func (s *Server) listLegacyPlayableModels(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Deprecation", "true")
|
||||
w.Header().Set("Link", "</api/v1/platform-models>; rel=\"successor-version\"")
|
||||
s.listPlayableModels(w, r)
|
||||
}
|
||||
|
||||
// listOpenAIModels godoc
|
||||
// @Summary 列出 OpenAI 兼容模型
|
||||
// @Description 按当前身份、API Key 访问规则及 scope 返回去重后的逻辑模型列表。
|
||||
// @Tags openai-compatible
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Success 200 {object} OpenAIModelListResponse
|
||||
// @Failure 401 {object} ErrorEnvelope
|
||||
// @Failure 500 {object} ErrorEnvelope
|
||||
// @Router /v1/models [get]
|
||||
func (s *Server) listOpenAIModels(w http.ResponseWriter, r *http.Request) {
|
||||
user, _ := auth.UserFromContext(r.Context())
|
||||
models, err := s.store.ListAccessiblePlatformModels(r.Context(), user)
|
||||
if err != nil {
|
||||
s.logger.Error("list openai models failed", "error", err)
|
||||
writeError(w, http.StatusInternalServerError, "list models failed")
|
||||
return
|
||||
}
|
||||
byID := map[string]OpenAIModel{}
|
||||
for _, model := range models {
|
||||
id := model.ModelName
|
||||
if id == "" {
|
||||
continue
|
||||
}
|
||||
created := model.CreatedAt.Unix()
|
||||
current, exists := byID[id]
|
||||
if !exists || created < current.Created {
|
||||
byID[id] = OpenAIModel{ID: id, Object: "model", Created: created, OwnedBy: "easyai"}
|
||||
}
|
||||
}
|
||||
data := make([]OpenAIModel, 0, len(byID))
|
||||
for _, model := range byID {
|
||||
data = append(data, model)
|
||||
}
|
||||
sort.Slice(data, func(i, j int) bool { return data[i].ID < data[j].ID })
|
||||
writeJSON(w, http.StatusOK, OpenAIModelListResponse{Object: "list", Data: data})
|
||||
}
|
||||
Reference in New Issue
Block a user