
LocalAI 新增 API 端点与认证/权限集成完全指南路由、Feature、鉴权三层架构与能力通告实践【免费下载链接】LocalAILocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required.项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI本指南面向在 LocalAI 中扩展 API 能力的开发者完整讲解如何新增一个受认证与权限系统保护的端点从三层鉴权中间件架构、路由注册与中间件组合到新增可开关的 Feature、处理错误响应、接入用量统计再到遍布 Swagger、/api/instructions、前端capabilities.js与文档站点的四处能力通告面。阅读并实践本文后你将能按仓库既有模式提交一个对其他客户端、管理员 UI 与 Agent 完全可见的新端点而不是一个能跑但没人知道存在的黑盒接口。三层鉴权架构总览在动手写代码前必须先理解认证与授权在 LocalAI 中如何分层流动。依据 api-endpoints-and-auth.md 的架构说明请求经过三层校验全局认证中间件auth.Middleware实现在 core/http/auth/middleware.go在 core/http/app.go 中对每个请求生效。它负责解析 session cookie、Authorization: Bearer、x-api-key/xi-api-key头、tokencookie 以及遗留 API Key并在 Echo context 中写入auth_user与auth_role。Feature 中间件auth.RequireFeature/auth.RequireRouteFeature对路由组或单条路由做按 Feature 的访问控制检查当前用户是否被授予特定能力。Admin 中间件auth.RequireAdmin把端点限制为仅 admin 用户可访问。当认证被禁用时无 auth DB、无遗留 API Key所有中间件退化为透传auth.NoopMiddleware。源码 middleware.go 中的判定逻辑与此一致authEnabled : db ! nil、hasLegacyKeys : len(appConfig.ApiKeys) 0两者皆为空时直接next(c)。全局中间件的实际解析顺序在 middleware.go 的注释中可以看到完整的解析顺序这是理解哪种凭据生效的关键认证未启用且无遗留 Key → 直接放行认证启用DB 非空时依次尝试a. session cookie→ DB 会话查询Web UIb.Authorization: Bearer→ 先按 session token 校验再按命名 API Key 校验c.x-api-key/xi-api-key→ 命名 API Keyd.tokencookie→ 先当命名 API Key 校验e. 兜底把所有渠道提取出的 Key 与遗留ApiKeys比对命中则构造一个合成的 admin 用户UsageSourceLegacy认证未启用 → 仅执行遗留 API Key 校验放行已认证请求、公开路由、PathWithoutAuth覆盖路径以及使用替代认证的路由组启用DisableApiKeyRequirementForHttpGet时对匹配HttpGetExemptedEndpoints正则的 GET 请求放行其余一律拒绝。中间件在 app.go 中的装配顺序在 core/http/app.go 中可以观察到实际装配顺序顺序本身即安全设计// 健康检查永远豁免认证最先注册 routes.HealthRoutes(e, application.Ready) // 全局认证中间件 authMiddleware : auth.Middleware(application.AuthDB(), application.ApplicationConfig()) e.Use(authMiddleware) // Feature 与模型访问控制必须在认证之后、路由之前注册 if application.AuthDB() ! nil { e.Use(auth.RequireRouteFeature(application.AuthDB())) e.Use(auth.RequireModelAccess(application.AuthDB())) e.Use(auth.RequireQuota(application.AuthDB())) }而 admin 中间件是按需传递而非全局注册的var adminMiddleware echo.MiddlewareFunc if application.AuthDB() ! nil { adminMiddleware auth.RequireAdmin() } else { adminMiddleware auth.NoopMiddleware() }随后adminMiddleware与各类 feature 中间件agentsMw、mcpMw、fineTuningMw等被传入Register*Routes系列函数见 core/http/app.go 与后续路由注册段。新增一个 API 端点Step 1编写 handlerhandler 应写在 core/http/endpoints 下合适的子包中遵循既有模式// core/http/endpoints/localai/my_feature.go package localai func MyFeatureEndpoint(app *application.Application) echo.HandlerFunc { return func(c echo.Context) error { // 用 auth.GetUser(c) 获取已认证用户认证禁用时可能为 nil user : auth.GetUser(c) // 你的业务逻辑 return c.JSON(http.StatusOK, result) } }Step 2注册路由在 core/http/routes 下按端点类别选择对应文件文件类别routes/openai.goOpenAI 兼容 API/v1/...routes/localai.goLocalAI 专有端点/api/...、/models/...、/backends/...routes/agents.goAgent 池端点/api/agents/...routes/auth.go认证端点/api/auth/...routes/ui_api.goUI 后端 API 端点Step 3选择合适的保护级别无需认证公开端点豁免路径完全绕过认证。在 middleware.go 的isExemptPath()中追加或使用/api/auth/前缀始终豁免。务必克制使用——绝大多数端点都应当要求认证。标准认证任意已登录用户全局中间件已处理这一切认证启用时/api/、/v1/等 API 路径会自动要求认证无需再叠加任何中间件router.GET(/v1/my-endpoint, myHandler) // 由全局中间件强制认证仅限 Admin把adminMiddleware传给路由。它由 core/http/app.go 装配后传入各Register*Routes// 在 Register 函数签名中接收该中间件 func RegisterMyRoutes(router *echo.Echo, app *application.Application, adminMiddleware echo.MiddlewareFunc) { router.POST(/models/apply, myHandler, adminMiddleware) }auth.RequireAdmin()的源码行为可见 middleware.go无用户返回 401authentication_error非 admin 角色返回 403authorization_error。Feature 门控方案 A路由组级中间件适合一组相关端点// 在 app.go 中创建 feature 中间件 myFeatureMw : auth.RequireFeature(application.AuthDB(), auth.FeatureMyFeature) // 传入路由注册函数 routes.RegisterMyRoutes(e, app, myFeatureMw) // 在 routes 文件中应用于路由组 g : e.Group(/api/my-feature, myFeatureMw) g.GET(, listHandler) g.POST(, createHandler)方案 BRouteFeatureRegistry适合单个 OpenAI 兼容端点在 core/http/auth/features.go 的RouteFeatureRegistry中追加条目全局中间件RequireRouteFeature会自动执行var RouteFeatureRegistry []RouteFeature{ // ... 既有条目 ... {POST, /v1/my-endpoint, FeatureMyFeature}, }RouteFeatureRegistry是端点 → feature映射的唯一事实来源被 core/http/auth/middleware.go 中RequireRouteFeature预构建成METHOD:pattern → feature的查找表支持*作为任意方法的通配。正则已存在的真实条目包括/v1/chat/completions → FeatureChat、/v1/audio/transcriptions → FeatureAudioTranscription、/v1/face/verify → FeatureFaceRecognition等几乎覆盖全部/v1/*推理路径。新增一个 Feature可开关能力当需要的不仅是某个既有 Feature 之下的新端点而是全新的可开关能力时按以下步骤推进对应文件为 core/http/auth/permissions.go 与 core/http/auth/features.go。1. 定义 Feature 常量在 core/http/auth/permissions.go 中追加常量并加入相应切片const ( // Agent 类 Feature新用户默认关闭 OFF FeatureMyFeature my_feature )// 默认 OFF —— 用户必须被显式授权 var AgentFeatures []string{..., FeatureMyFeature} // 默认 ON —— 用户默认可用、除非被显式撤销 var APIFeatures []string{..., FeatureMyFeature}源码中三类切片划分得很清晰permissions.goAgentFeatures默认 OFFagents、skills、collections、mcp_jobs、localai_assistantGeneralFeatures默认 OFFfine_tuning、quantizationAPIFeatures默认 ONchat、images、audio_speech、audio_transcription、audio_diarization、audio_classification、vad、detection、video、3d、embeddings、sound、realtime、moderation、rerank、tokenize、mcp、stores、face_recognition、voice_recognition、audio_transform、pii_filter。默认开关语义由defaultOnFeatures集合与isDefaultOnFeature()permissions.go统一判定权限表里缺键时API 类 Feature 视为开、Agent/General 类视为关。2. 补充 Feature 元数据在 core/http/auth/features.go 的对应*FeatureMetas()函数中追加条目管理 UI 才能展示它func AgentFeatureMetas() []FeatureMeta { return []FeatureMeta{ // ... 既有条目 ... {FeatureMyFeature, My Feature, false}, // false 默认 OFF } }FeatureMeta结构体Key / Label / DefaultValue就是/api/...权限接口与前端渲染的元数据来源。3. 装配中间件在 core/http/app.go 中myFeatureMw : auth.RequireFeature(application.AuthDB(), auth.FeatureMyFeature)再把它传给路由注册函数。auth.RequireFeature()middleware.go的判定规则值得注意admin 永远通过普通用户取缓存权限GetCachedUserPermissions键缺失时按是否默认开启判定被拒则统一返回 403feature not enabled for your account。4. 注册路由-Feature 映射如适用若该 Feature 门控的是标准 API 端点如/v1/...应改在features.go的RouteFeatureRegistry中登记而不是用逐路由中间件——这与清单里所有/v1/*路由都经由 registry 门控而非逐路由中间件的约定一致。在 handler 中访问已认证用户认证完成后handler 内可通过 core/http/auth/middleware.go 导出的辅助函数读取用户上下文import github.com/mudler/LocalAI/core/http/auth func MyHandler(c echo.Context) error { // 获取用户认证禁用或未认证时为 nil user : auth.GetUser(c) if user nil { // 处理未认证——或交给中间件 } // 检查角色 if user.Role auth.RoleAdmin { // admin 专属逻辑 } // 程序化检查 Feature 权限需要条件行为而非整体拦截时 if auth.HasFeatureAccess(db, user, auth.FeatureMyFeature) { // feature 专属逻辑 } // 检查模型访问权限 if !auth.IsModelAllowed(db, user, modelName) { return c.JSON(http.StatusForbidden, ...) } }此外还有三个补充访问器auth.GetUserRole(c)返回角色字符串auth.GetAPIKey(c)返回命中的*UserAPIKeysession cookie 与遗留 Key 认证时为 nilauth.GetSource(c)返回认证来源UsageSourceWeb/UsageSourceAPIKey/UsageSourceLegacy。权限判定层在 permissions.goHasFeatureAccessadmin 恒 true缺键按默认值、IsModelAllowedadmin 或 allowlist 关闭时放行、GetModelAllowlist/UpdateModelAllowlist维护模型白名单。全局中间件RequireModelAccessmiddleware.go则直接从 path 参数、query、JSON body 或 form 值提取模型名做拦截。中间件组合模式中间件可在不同层级组合仓库中存在三种典型模式路由组级agents 模式// 组内所有路由共享中间件 g : e.Group(/api/agents, poolReadyMw, agentsMw) g.GET(, listHandler) g.POST(, createHandler)逐路由localai 模式// 单个路由以附加参数获得中间件 router.POST(/models/apply, applyHandler, adminMiddleware) router.GET(/metrics, metricsHandler, adminMiddleware)中间件切片openai 模式// 为某个 handler 构建中间件链 chatMiddleware : []echo.MiddlewareFunc{ usageMiddleware, traceMiddleware, modelFilterMiddleware, } app.POST(/v1/chat/completions, chatHandler, chatMiddleware...)错误响应格式与状态码约定鉴权/权限错误一律使用schema.ErrorResponse以保持与 OpenAI 兼容 API 的一致性return c.JSON(http.StatusForbidden, schema.ErrorResponse{ Error: schema.APIError{ Message: feature not enabled for your account, Code: http.StatusForbidden, Type: authorization_error, }, })仓库中统一的状态码语义401 Unauthorized—— 未提供有效凭据RequireAdmin、RequireFeature在无用户时返回全局中间件的authError还会设置WWW-Authenticate: Bearer并在启用OpaqueErrors时只返回空响应体以隐藏细节403 Forbidden—— 已认证但缺少权限角色不足 / feature 未开 / 模型不在白名单429 Too Many Requests—— 被限流认证端点场景配额中间件RequireQuota会同时设置Retry-After响应头并返回quota_exceeded类型错误。接入用量统计若端点需要被用量追踪token 计数、请求计数把usageMiddleware加入其中间件链即可。其实现位于 core/http/middleware/usage.go在 routes/openai.go 中可以观察它如何与 trace、modelFilter 等中间件一起作用于/v1/chat/completions。来源区分见auth.GetSourceWeb 会话、命名 API Key 与遗留 Key 的用量会被归入不同来源。分布式模式控制平面数据库健康指标在分布式模式下前端会向 PostgreSQL 控制平面数据库注册三个 OpenTelemetry gauge实现在 core/services/monitoring/control_plane_db.go由 core/application/distributed.go 装配并通过与其余 API 指标相同的 Prometheus exporter 暴露到/metricsMetric含义何时报警localai_control_plane_oldest_xmin_age自某个后端仍持有的最老快照以来的事务耗时达到数百万级且持续上升localai_control_plane_longest_transaction_seconds最久未结束的打开事务的存活时长超过 3600localai_control_plane_dead_tuple_ratio死元组与活元组之比按table打标签作用于backend_nodes、node_models、gallery_operations小表上持续超过约 10持续偏高的localai_control_plane_oldest_xmin_age是应优先处理的那一个只要它不断增长autovacuum 无论运行多少次都无法回收库内任何空间死元组占比会持续攀升——一张只有六行的注册表都可能膨胀到数百 MB。此时调优 autovacuum 无济于事正确做法是找出持有该 horizon 的事务并清理它SELECT pid, state, age(backend_xmin) AS xmin_age, now() - xact_start AS xact_age, query FROM pg_stat_activity WHERE backend_xmin IS NOT NULL ORDER BY age(backend_xmin) DESC;随后对肇事的会话执行pg_terminate_backend(pid)等 horizon 前移后再对膨胀表执行VACUUM (VERBOSE)。一个看起来健康的 xmin age 并不能单独证明 horizon 已释放。该 gauge 读取的是pg_stat_activity它只能看到存活的后端。还有两样东西会钉住同一个 horizon 且在此不可见任其之一都可能在 gauge 读数为 0 时继续阻塞 vacuumSELECT gid, prepared, database, transaction FROM pg_prepared_xacts; SELECT slot_name, active, xmin, catalog_xmin FROM pg_replication_slots;孤儿预准备事务可用ROLLBACK PREPARED gid清除过期的复制槽用pg_drop_replication_slot(slot_name)删除。在断定某张膨胀表另有原因之前务必先排查这两项。采样是由抓取驱动、背后带 30 秒缓存的因此抓取频率不会转化为数据库负载失败的样本与超时的样本会消耗与成功样本相同的间隔不会在数据库已经吃力时每个 scrape 周期反复重试。失败样本上报的是上一次成功值而非让本次抓取失败——因为这些 gauge 恰恰在数据库挣扎时最有意义。首次成功采样前 gauge 是缺失而非 0因为 xmin age 为 0 会被误读成健康 horizon若需区分健康与从未采样请同时对absent()报警。能力通告面新能力需要登记在四个地方路由与鉴权之外LocalAI 在四个相互独立的地方发布自身能力表面。新增端点——尤其是引入全新能力新媒体类型、新鉴权 Feature时——必须同步更新每个相关表面。这些不是可选项漏掉任何一个都意味着端点能用但客户端、管理员与 UI 都不知道它存在。1. SwaggerTags注解强制每个 handler 都需要 swagger 注解块端点才会出现在/swagger/index.html与/api/instructions输出中。Tags的值决定端点归入哪个能力区域// MyEndpoint does X. // Summary Do X. // Tags my-capability // Param request body schema.MyRequest true payload // Success 200 {object} schema.MyResponse Response // Router /v1/my-endpoint [post] func MyEndpoint(...) echo.HandlerFunc { ... }当端点是扩展现有区域如audio、images、face-recognition时沿用既有 tag仅当引入全新能力表面时才新建 tag——并且必须随之在通告面 2 中登记。改完注解后需重新生成内嵌 spec 使运行时生效make protogen-go # 先确保 gRPC 代码生成是最新的 make swagger # 重新生成 swagger/swagger.json2./api/instructions注册表新增能力区域时core/http/endpoints/localai/api_instructions.go 定义了instructionDefs——一个轻量、机器可读的能力区域索引把 swagger 端点按 tag 分组。它是 Agent 与 SDK 发现服务能力的首要入口这台服务器能做什么。何时更新仅在新增能力区域新 swagger tag时。既有 tag 下的新端点会自动浮出无需改动这里。向instructionDefs追加条目{ Name: my-capability, // /api/instructions/my-capability 的 URL 段 Description: Short sentence describing the capability, Tags: []string{my-capability}, // 必须与 swagger Tags 一致 Intro: Optional gotcha/context that isnt in the swagger descriptions (caveats, defaults, cross-references to other endpoints)., },同时要更新 api_instructions_test.go 对应测试中的期望数量并把新名字加进ContainElements断言。3.capabilities.js符号新增模型配置FLAG_*标志时若新能力需要 core/config/model_config.go 中的新FLAG_*usecase 标志用户可据此过滤 gallery 模型/v1/models也会据此暴露该能力则必须同步更新全部以下位置core/config/backend_capabilities.go 中的UsecaseName字符串常量把该字符串映射到标志 gRPC 方法的UsecaseInfoMap条目core/config/model_config.go 中的FLAG_NAME位掩码GetAllModelConfigUsecases()映射条目否则 YAML 加载器会静默忽略该字符串若该标志影响IsMultimodal()需加入ModalityGroups成员例如 realtime_audio 同时属于 speech-input 与 audio-output 两组单独一个标志也能读作多模态GuessUsecases()中列出拥有该能力的后端的分支core/http/routes/ui_api.go 中的usecaseFilters驱动 gallery 筛选下拉框core/http/react-ui/public/locales/en/models.json 中Models.jsx的FILTERS数组及配套的filters.camelCasei18n 键core/http/react-ui/src/utils/capabilities.jsexport const CAP_MY_CAPABILITY FLAG_MY_CAPABILITY想按能力过滤 ModelSelector 的 React 页面会 import 此符号。即便你暂不实现 UI 页面也应声明它——声明本身保证了 Go/JS 两侧词汇表保持一致。4.docs/content/面向用户的文档新能力值得在 docs/content/features 下拥有独立页面并与相关功能页互相交叉链接。宣传新能力是发布release的职责不在本文范畴能力会在 website/content/blog 下的发布博客文章中覆盖docs/content/whats-new.md 只是指向博客与 GitHub Releases 的指针因此那里无需新增内容。路径保护规则全局认证中间件把路径划分为 API 路径与非 API 路径API 路径认证启用时一律要求认证/api/、/v1/、/models/、/backends/、/backend/、/tts、/vad、/video、/stores/、/system、/ws/、/metrics豁免路径永不要求认证/api/auth/前缀以及appConfig.PathWithoutAuth中配置的任意路径非 API 路径UI、静态资源直接放行——登录跳转由 React UI 在客户端完成。若你在新的顶层路径前缀下新增端点请把该前缀加入 middleware.go 的isAPIPath()确保它要求认证。值得补充的是公开路由本身也有一份白名单式的注册表见 core/http/auth/public_routes.go 中的publicRouteRegistry——GET /healthz、GET /readyz、GET /api/instructions、GET /swagger/...、认证引导端点/api/auth/login、/api/auth/register、GET /api/auth/status等、SPA 页面与静态资源都在其中。新增全公开端点前先对照这份清单判断它究竟该进豁免路径、公开路由还是更常见保持需要认证。另外/api/node/前缀走的是usesAlternativeAuthentication()所标识的路由组替代认证路径节点自服务使用注册 token 等独立凭据体系全局认证中间件会对其放行。发布前核对清单新增端点时逐项核对原文清单完整收录如下路由与鉴权handler 位于core/http/endpoints/路由已注册在合适的core/http/routes/文件中已选择鉴权级别公开 / 标准 / admin / feature 门控已在core/http/auth/features.go的RouteFeatureRegistry中登记条目每条路由一个方法——所有/v1/*路由都经由此表门控而非逐路由中间件若是新 Featurepermissions.go中定义了常量加入正确的切片APIFeatures默认开 /AgentFeatures默认关并在features.go的*FeatureMetas()中补充元数据若 Feature 使用组中间件在core/http/app.go中装配并传给路由注册函数若是新路径前缀已加入middleware.go的isAPIPath()若需 token 计数已把usageMiddleware加入中间件链能力通告面易遗漏——参见上文能力通告面一节handler 上有完整 Swagger 块Summary、Tags、Param、Success、Router若是新能力区域新 swagger tag在core/http/endpoints/localai/api_instructions.go的instructionDefs登记 api_instructions_test.go中更新计数若是新FLAG_*usecase 标志已从core/http/react-ui/src/utils/capabilities.js导出对应的CAP_*符号已创建docs/content/features/feature.md已与相关功能页交叉链接能力已列入发布博客参见 .agents/preparing-a-release.md质量错误响应使用schema.ErrorResponse格式或用映射了 gRPC 状态的echo.NewHTTPError——参见 core/http/endpoints/localai/images.go 的mapBackendError辅助函数测试同时覆盖已认证与未认证访问改动任何Router/Tags/Param注解后已重新生成 Swaggermake swagger配套MCP admin 工具面admin 端点必需。每个新 admin 端点都必须考虑 MCP admin 工具表面——否则 REST API 与 MCP 工具目录会悄然漂移而 LocalAI Assistant 对话模态与独立的local-ai mcp-server都依赖 pkg/mcp/localaitools 来镜像 REST。结果只有两种可接受、一种不可接受添加了工具新端点适合管理员以对话方式管理安装、列出、编辑、开关、升级。请完整遵循 .agents/localai-assistant-mcp.md 中的清单添加LocalAIClient接口方法在inproc与httpapi两个实现中各实现一次以Tool*常量注册工具更新技能提示词并把路由加入 pkg/mcp/localaitools/coverage_test.go 的toolToHTTPRoute刻意跳过工具端点是内部/诊断性质的添加对话路径反而会产生误导。在 PR 描述中记录该决定即可无需代码动作遗漏这会破坏契约。pkg/mcp/localaitools中的TestToolHTTPRouteMappingComplete测试只是部分防线它只校验每个Tool*都有路由映射检测不到没有对应工具的 REST 新端点——这仍是对 PR 作者的流程检查。请在清单末尾追加若为 admin 端点已决策是否需要 MCP 覆盖需要则工具已注册并更新映射不需要则在 PR 描述中写明跳过理由。小结在 LocalAI 中落地一个高质量的 API 端点远不止写 handler 挂路由。真正决定端点成熟度的是三件事鉴权分层选型全局认证 / Feature 门控 / admin 专用之间做出正确取舍、错误与用量约定统一schema.ErrorResponse、正确的 401/403/429 语义、是否接入usageMiddleware以及四处能力通告面的同步Swagger 注解、/api/instructions、前端capabilities.js与文档站。把本文清单作为路由设计时的自检基线再以 api-endpoints-and-auth.md 为随时回溯的规范原文配合仓库中 core/http/auth 与 core/http/routes 的真实代码模式即可让新端点从一开始就对客户端、管理员 UI 与 Agent 生态完全可见、可管理、可审计。【免费下载链接】LocalAILocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required.项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考