首页
/ LocalAI 认证与授权实战:从 API Key 到多用户 RBAC、OAuth/OIDC 与用量追踪

LocalAI 认证与授权实战:从 API Key 到多用户 RBAC、OAuth/OIDC 与用量追踪

2026-09-08 11:24:10作者:齐冠琰

LocalAI 默认以「开箱即用」的方式对外提供服务,但在生产环境中你需要为实例加上访问控制。本文基于 LocalAI 官方特性文档 Authentication & Authorization 并结合仓库源码,系统讲解两套认证机制:legacy API Key 认证(共享密钥)与完整的多用户认证体系(角色、会话、OAuth/OIDC、按用户用量追踪),以及二者同时启用时的授权回退顺序。读完本文,你将掌握如何通过环境变量启用认证、理解「私有一切、显式放行」的路由鉴权模型、为团队配置 GitHub OAuth / OIDC 单点登录,并利用 invite 邀请码、用户级 API Key 与用量面板落地多租户治理。

双认证模式总览

LocalAI 提供两种相互独立的认证模式:

  1. Legacy API Key 认证(legacy):通过一个或多个共享密钥保护整个实例,简单直接,但所有 Key 一律拥有完整管理员权限,无角色区分;
  2. 用户认证系统(user auth):基于数据库存储的用户、角色、会话与个人 API Key,支持管理员/普通用户两级 RBAC、注册审批流、邀请链接、GitHub OAuth 与通用 OIDC 单点登录,并对每个用户、每个 API Key 做 token 用量追踪。

两条路线可叠加使用(见下文「组合认证模式」),用于从共享 Key 平滑迁移到多用户账户体系。关键区别一句话概括:legacy Key 是「门禁」,能进门的都是管理员;用户体系则是「门禁 + 分诊」,进门后还要看角色和权限。

Legacy API Key 认证

Legacy API Key 是保护 LocalAI 实例成本最低的方式。通过环境变量或 CLI flag 设置一个或多个 Key:

# 单 Key
LOCALAI_API_KEY=sk-my-secret-key localai run

# 多 Key(逗号分隔)
LOCALAI_API_KEY=key1,key2,key3 localai run

在源码中该配置项位于 core/cli/run.go,同时支持别名 API_KEY,最终注入 ApplicationConfig.ApiKeys

APIKeys []string `env:"LOCALAI_API_KEY,API_KEY" help:"List of API Keys to enable API authentication..."`

客户端可通过以下任意一种方式携带 Key:

  • Authorization: Bearer <key> 请求头
  • x-api-key: <key> 请求头
  • xi-api-key: <key> 请求头
  • token Cookie

对应的提取逻辑在 core/http/auth/middleware.goextractKey 函数中,四种来源被统一解析为待校验的密钥字符串。校验时使用常量时间比较(crypto/subtle.ConstantTimeCompare)防止时序侧信道攻击,见 middleware.go

Legacy API Key 授予完整管理员权限,不存在角色隔离。 当认证开启时,命中 legacy Key 的请求会在中间件中被构造成一个合成的管理员用户(ID 为 legacy-api-key,角色 admin),见 middleware.go

syntheticUser := &User{
    ID:   "legacy-api-key",
    Name: "API Key User",
    Role: RoleAdmin,
}
c.Set(contextKeyUser, syntheticUser)
c.Set(contextKeyRole, RoleAdmin)

因此,凡是需要多用户按角色隔离权限的部署场景,应当改用用户认证系统。

此外,API Key 还可在运行期通过 Runtime Settings 界面管理,相关文档见 Runtime Settings

受保护路由与匿名路由

当配置了数据库认证(用户体系)或 legacy API Key 后,LocalAI 的 HTTP 面默认全部私有。匿名请求只有在满足以下条件之一时才能通过:

  • 命中「公共发现 API」或「匿名引导路由」白名单;
  • 命中显式部署级豁免(PathWithoutAuth 前缀);
  • 命中 legacy GET 豁免正则;
  • 命中采用替代认证方式的路由组(如 /api/node/ 前缀)。

如果两种认证模式都未配置,鉴权中间件不做任何限制,全部请求放行。

这一「白名单判断」模型在 core/http/auth/public_routes.goisPublicRoute 中实现——先精确匹配,再按以 / 结尾的 Prefix 规则做前缀匹配;整体判断流程见 middleware.go,中间件按「已认证 → 公共路由 → PathWithoutAuth 覆盖 → 替代认证 → legacy GET 豁免 → 拒绝」的顺序执行。

公开发现 API

以下发现类请求无需凭据即可匿名访问:

  • GET /.well-known/localai.json
  • GET /api/instructions
  • GET /api/instructions/{name}
  • /swagger/swagger/ 下的 Swagger GET 请求

注意:这些发现 API 只描述服务器的接口面,它们对外宣告的端点本身仍然需要凭据,除非该端点同样出现在公开名单或引导路由名单中。

对应源码注册见 public_routes.go

// Discovery.
{Method: http.MethodGet, Path: "/api/instructions"},
{Method: http.MethodGet, Path: "/api/instructions/", Prefix: true},
{Method: http.MethodGet, Path: "/swagger"},
{Method: http.MethodGet, Path: "/swagger/", Prefix: true},
{Method: http.MethodGet, Path: "/.well-known/localai.json"},

匿名引导路由

为支撑健康检查、凭据获取与登录 UI,LocalAI 允许以下请求匿名通过,但这不会让 API 的其他部分变得公开:

  • 健康检查:GET /healthzGET /readyz
  • 认证状态与 token 登录:GET /api/auth/statusPOST /api/auth/token-login
  • 本地注册与登录:POST /api/auth/registerPOST /api/auth/login
  • GitHub OAuth:GET /api/auth/github/loginGET /api/auth/github/callback
  • OIDC:GET /api/auth/oidc/loginGET /api/auth/oidc/callback
  • 认证预检请求:/api/auth/ 下的 OPTIONS
  • SPA 壳路由:GET /HEAD /,以及 /app/browse/login/invite/*/explorerGET/app//browse/ 子路径也通过 GET 放行
  • SPA 静态资源:GET /favicon.svg,以及 /assets//locales//static/ 下的 GET
  • 品牌读取:GET /api/branding/branding/asset/ 下的 GET品牌修改仍需管理员凭据

上述规则完整对应 public_routes.gopublicRouteRegistry 的三个分组(Health / Authentication bootstrap / SPA / Assets / Branding),可作为排查「为什么某个路由免鉴权」的第一手依据。

需要凭据的路由

在没有显式部署豁免的前提下,其余所有路由都需要凭据,包括 GET /version、全部模型与后端管理 API、全部推理路由。MCP 与 moderation 别名路由同样是私有的:

  • POST /v1/mcp/chat/completionsPOST /mcp/v1/chat/completionsPOST /mcp/chat/completions
  • POST /v1/moderationsPOST /moderations

生成内容的输出 URL 同样受保护,覆盖 /generated-audio//generated-images//generated-videos//generated-3d/ 下的所有 URL。

显式部署豁免(overrides)

嵌入式部署可以向 ApplicationConfig.PathWithoutAuth 追加路径前缀。命中前缀后,该前缀下的所有 HTTP 方法都会绕过全局认证(但路由自身注册的路由级鉴权仍会执行)。因此应尽量将豁免范围收窄,默认列表为空。

PathWithoutAuth 的校验在 middleware.goisExemptPath 中通过字符串前缀匹配完成,配置结构定义见 application_config.go,且测试 middleware_test.go 明确验证了「调用方提供的自定义前缀」会被保留。

另有两个 legacy flag 提供GET 的兼容性豁免(仅在配置了 legacy API Key 时生效):

  • LOCALAI_DISABLE_API_KEY_REQUIREMENT_FOR_HTTP_GET=true:开启该豁免开关;
  • LOCALAI_HTTP_GET_EXEMPTED_ENDPOINTS:设置被豁免的 GET 路由正则表达式列表。

core/cli/run.go 中可以看到两个 flag 的定义与默认正则:

DisableApiKeyRequirementForHttpGet bool     `env:"LOCALAI_DISABLE_API_KEY_REQUIREMENT_FOR_HTTP_GET" default:"false" help:"If true, a valid API key is not required to issue GET requests to portions of the web ui..." group:"hardening"`
HttpGetExemptedEndpoints           []string `env:"LOCALAI_HTTP_GET_EXEMPTED_ENDPOINTS" default:"^/$,^/app(/.*)?$,^/browse(/.*)?$,^/login/?$,^/explorer/?$,^/assets/.*$,^/static/.*$,^/swagger.*$" help:"..." group:"hardening"`

默认豁免正则覆盖 //app/browse/login/explorer/assets/static/swagger 的 GET 请求,恰好对应 Web UI 的 SPA 静态资源。端点表达式只有在开启 LOCALAI_DISABLE_API_KEY_REQUIREMENT_FOR_HTTP_GET 时才生效,自定义表达式需要谨慎审查,因为可能把受保护的读取接口暴露出去。中间件对该豁免的执行逻辑见 middleware.go,仅当 Method == GET 且匹配任意正则时才放行。

用户认证系统

用户认证系统提供以下能力:

  • 用户账户:email、姓名与头像
  • 基于角色的访问控制(RBAC):admin 与 user 两级
  • 基于会话的认证:安全 Cookie
  • OAuth 登录(GitHub)与 OIDC 单点登录(Keycloak、Google、Okta、Authentik 等)
  • 按用户的 API Key:面向程序化访问
  • 管理路由门禁:管理端点仅限 admin
  • 按用户用量追踪:token 消耗指标

启用认证

设置 LOCALAI_AUTH=true,或提供 GitHub OAuth Client ID / OIDC Client ID(会自动启用认证):

# 启用并使用 SQLite(默认,存储于 {DataPath}/database.db)
LOCALAI_AUTH=true localai run

# 启用并使用 GitHub OAuth
GITHUB_CLIENT_ID=your-client-id \
GITHUB_CLIENT_SECRET=your-client-secret \
LOCALAI_BASE_URL=http://localhost:8080 \
localai run

# 启用并使用 OIDC 提供商(如 Keycloak)
LOCALAI_OIDC_ISSUER=https://keycloak.example.com/realms/myrealm \
LOCALAI_OIDC_CLIENT_ID=your-client-id \
LOCALAI_OIDC_CLIENT_SECRET=your-client-secret \
LOCALAI_BASE_URL=http://localhost:8080 \
localai run

# 启用并使用 PostgreSQL
LOCALAI_AUTH=true \
LOCALAI_AUTH_DATABASE_URL=postgres://user:pass@host/dbname \
localai run

配置项参考

环境变量 默认值 说明
LOCALAI_AUTH false 启用用户认证与授权
LOCALAI_AUTH_DATABASE_URL {DataPath}/database.db 数据库 URL——PostgreSQL 用 postgres://...,文件路径则使用 SQLite(同时兼容别名 DATABASE_URL
GITHUB_CLIENT_ID GitHub OAuth App Client ID(设置后自动启用认证)
GITHUB_CLIENT_SECRET GitHub OAuth App Client Secret
LOCALAI_OIDC_ISSUER OIDC issuer URL,用于自动发现(如 https://accounts.google.com
LOCALAI_OIDC_CLIENT_ID OIDC Client ID(设置后自动启用认证)
LOCALAI_OIDC_CLIENT_SECRET OIDC Client Secret
LOCALAI_BASE_URL OAuth 回调使用的对外 Base URL(如 http://localhost:8080
LOCALAI_ADMIN_EMAIL 登录时自动提升为 admin 角色的邮箱地址
LOCALAI_REGISTRATION_MODE approval 注册模式:openapprovalinvite
LOCALAI_DISABLE_LOCAL_AUTH false 禁用本地 email/密码注册与登录(用于仅 OAuth/OIDC 的部署)

源码层面,这些变量统一由 core/cli/run.goauth 配置组声明,并映射进 ApplicationConfig.Auth(类型 AuthConfig,见 core/config/application_config.go)。其中还包含两个文档未在表格中列出的进阶项:LOCALAI_AUTH_HMAC_SECRET(API Key / 会话 / 邀请码的 HMAC 哈希密钥,留空自动生成)与 LOCALAI_DEFAULT_API_KEY_EXPIRY(API Key 默认过期时长,如 90d1y,空表示不过期)。

网络存储警告。 基于文件的 SQLite 依赖 POSIX 文件锁,在网络文件系统上(SMB/CIFS/NFS,例如 Azure Files / Azure Container Apps 共享卷)并不可靠。此类存储上的认证数据库可能以 database is locked 报错导致迁移失败。当数据目录位于共享/网络存储时请改用 PostgreSQL(LOCALAI_AUTH_DATABASE_URL=postgres://...),或将 database.db 放在本地卷上。

需要说明:LOCALAI_REGISTRATION_MODE 在官方文档中的默认记录为 approval;在 core/cli/run.go 中该 flag 的帮助文本将 open 声明为 default 值,实际生效语义以 core/http/auth 中注册流程对三种模式(含 approval 待审批)的处理为准,生产部署建议显式设置该变量。

禁用本地认证

若希望强制仅使用 OAuth/OIDC 登录,阻止用户以 email/密码注册或登录,可设置 LOCALAI_DISABLE_LOCAL_AUTH=true(或传 --disable-local-auth):

# 仅 OAuth 的配置(无 email/密码)
LOCALAI_DISABLE_LOCAL_AUTH=true \
GITHUB_CLIENT_ID=your-client-id \
GITHUB_CLIENT_SECRET=your-client-secret \
LOCALAI_BASE_URL=http://localhost:8080 \
localai run

禁用后:

  • 登录页不显示 email/密码表单(UI 通过 /api/auth/status 返回的 providers 列表判断);
  • POST /api/auth/register 返回 403 Forbidden
  • POST /api/auth/login 返回 403 Forbidden
  • OAuth/OIDC 登录不受影响,正常工作。

角色

系统只有两种角色:

  • Admin(管理员):可访问全部端点,包括模型管理、后端配置、系统设置、追踪、agent 与用户管理。
  • User(普通用户):仅可访问推理端点——chat completions、embeddings、图像/视频/音频生成、TTS、MCP chat,以及自己的用量统计。

第一个登录的用户会被自动授予 admin 角色。 后续用户可通过管理员的用户管理 API 提升为 admin,或在启动时用 LOCALAI_ADMIN_EMAIL 指定其邮箱实现自动提升。

这一逻辑与源码 core/http/auth/roles.goAssignRole 完全对应:在创建用户的同一事务中统计用户总数,第一条记录(count == 0)返回 RoleAdmin;否则若邮箱与 adminEmail 匹配(大小写不敏感)也返回 RoleAdmin;其余返回 RoleUser。同一文件中还定义了 StatusActive = "active"StatusPending = "pending"StatusDisabled = "disabled" 三种用户状态。

从数据库模型 core/http/auth/models.go 可以看到 User 结构不仅存角色与状态,还保存 Providerlocal / github / oidc / agent-worker,见常量定义)与 PasswordHash(bcrypt 哈希,OAuth-only 用户为空)。

注册模式

模式 说明
open 任何人都能注册并立即生效
approval 新用户处于 pending 状态,等待管理员批准;若注册时提供了有效邀请码则立即激活(跳过审批等待)。(默认)
invite 注册必须使用管理员生成的邀请链接;没有邀请则注册被拒绝

OAuth 回调中的新用户创建逻辑(core/http/auth/oauth.go)在事务内按模式处理:invite 模式无邀请码直接报 invite_required,邀请码无效报 invalid_inviteapproval 模式则创建 pending 用户。

邀请链接

管理员可在 Web UI 的 Users → Invites 标签页生成单次使用、限时的邀请链接,或通过 API 创建:

# 创建邀请链接(默认 7 天过期)
curl -X POST http://localhost:8080/api/auth/admin/invites \
  -H "Authorization: Bearer <admin-key>" \
  -H "Content-Type: application/json" \
  -d '{"expiresInHours": 168}'

# 列出全部邀请
curl http://localhost:8080/api/auth/admin/invites \
  -H "Authorization: Bearer <admin-key>"

# 撤销未使用的邀请
curl -X DELETE http://localhost:8080/api/auth/admin/invites/<invite-id> \
  -H "Authorization: Bearer <admin-key>"

把邀请 URL(/invite/<code>)分享给用户,打开后注册表单会预填邀请码。LocalAI 仅在用户提交注册时才校验邀请码。邀请码单次使用、不可复用;过期或已用邀请会被拒绝。

core/http/auth/models.go 中,InviteCode 只保存邀请码的 HMAC-SHA256 哈希Code 字段,唯一索引)与用于展示的前缀 CodePrefix,原始邀请码不落库——与用户 API Key 的存储策略一致。

对于 GitHub OAuth,邀请码以查询参数附加在登录 URL 上(/api/auth/github/login?invite_code=<code>),并在 OAuth 流程期间存入 Cookie(见 oauth.go);OIDC 的邀请码机制与 GitHub OAuth 相同(/api/auth/oidc/login?invite_code=<code>)。

仅管理员端点

启用认证后,以下端点要求 admin 角色(中间件为 middleware.goRequireAdmin,返回 401 Unauthorized / 403 Forbidden 的标准错误结构):

模型与后端管理:

  • GET /api/modelsPOST /api/models/install/*POST /api/models/delete/*
  • GET /api/backendsPOST /api/backends/install/*POST /api/backends/delete/*
  • GET /api/operationsPOST /api/operations/*/cancelPOST /api/operations/*/pausePOST /api/operations/*/dismiss
  • GET /api/operations/historyDELETE /api/operations/history
  • GET /models/availableGET /models/galleriesGET /models/jobs/*
  • GET /backendsGET /backends/availableGET /backends/galleries

系统与监控:

  • GET /api/tracesGET /api/traces/summaryGET /api/traces/{id}POST /api/traces/clear
  • GET /api/backend-tracesGET /api/backend-traces/{id}POST /api/backend-traces/clear
  • GET /api/backend-logs/*POST /api/backend-logs/*/clear
  • GET /api/resourcesGET /api/settingsPOST /api/settings
  • GET /systemGET /backend/monitorPOST /backend/shutdownPOST /backend/load

P2P:

  • GET /api/p2p/*

Agents 与 Jobs:

  • 所有 /api/agents/* 端点
  • 所有 /api/agent/tasks/*/api/agent/jobs/* 端点

所有已认证用户可访问的端点:

  • POST /v1/chat/completionsPOST /v1/embeddingsPOST /v1/completions
  • POST /v1/images/generationsPOST /v1/audio/*POST /ttsPOST /vadPOST /video
  • GET /v1/modelsPOST /v1/tokenizePOST /v1/detokenizePOST /v1/detection
  • POST /v1/mcp/chat/completionsPOST /v1/messagesPOST /v1/responses
  • POST /stores/*GET /api/cors-proxy
  • GET /versionGET /api/featuresGET /metrics
  • GET /api/auth/usage(自己的用量数据)

除纯角色门禁外,源码还提供了更细粒度的授权中间件:RequireFeature 与基于 RouteFeatureRegistryRequireRouteFeature 检查用户功能开关(agentsskillscollectionsmcp_jobs 等),RequireModelAccess 依据 ModelAllowlist 校验用户可用的模型(从路径参数/查询参数/JSON 体/form 值中提取模型名,见 extractModelFromRequest),而 RequireQuota 则在推理路由上强制按用户配额并返回 429 + Retry-After。权限数据模型 UserPermission / PermissionMap / ModelAllowlist 均定义在 models.go

Web UI 访问控制

启用认证后,React UI 侧边栏会根据用户角色动态显示/隐藏区块:

  • 所有用户可见:Home、Chat、Images、Video、TTS、Sound、Talk、Usage、API docs 链接
  • 管理员额外可见:Models,Build 控制台(Agents、Skills、Memory、Jobs、Training、Recognition),Operate 控制台(Backends、Activity、Nodes、Usage、Traces、Users、Middleware、Settings)

仅管理员的页面在路由层也有保护——直接访问管理 URL 时,非管理员会被重定向回首页。

GitHub OAuth 配置

  1. 在 GitHub Settings → Developer settings → OAuth Apps → New OAuth App 创建 OAuth App;
  2. Authorization callback URL 设为 {LOCALAI_BASE_URL}/api/auth/github/callback
  3. 设置环境变量 GITHUB_CLIENT_IDGITHUB_CLIENT_SECRET
  4. LOCALAI_BASE_URL 设为可公开访问的 URL。

OIDC 配置

任何兼容 OIDC 的身份提供商均可用于单点登录,包括 Keycloak、Google、Okta、Authentik、Azure AD 等。

步骤:

  1. 在 OIDC 提供商处创建客户端/应用;
  2. 将重定向 URL 设为 {LOCALAI_BASE_URL}/api/auth/oidc/callback
  3. 设置三个环境变量:LOCALAI_OIDC_ISSUERLOCALAI_OIDC_CLIENT_IDLOCALAI_OIDC_CLIENT_SECRET

LocalAI 使用 OIDC 自动发现机制(/.well-known/openid-configuration),并请求标准 scope:openidprofileemail。签名算法等安全细节在 core/http/auth/oauth_signing_algs_test.go 有对应测试覆盖。

提供商示例:

# Keycloak
LOCALAI_OIDC_ISSUER=https://keycloak.example.com/realms/myrealm

# Google
LOCALAI_OIDC_ISSUER=https://accounts.google.com

# Authentik
LOCALAI_OIDC_ISSUER=https://authentik.example.com/application/o/localai/

# Okta
LOCALAI_OIDC_ISSUER=https://your-org.okta.com

用户 API Key

已认证用户可以创建个人 API Key 用于程序化访问:

# 创建 API Key(需要会话认证)
curl -X POST http://localhost:8080/api/auth/api-keys \
  -H "Cookie: session=<session-id>" \
  -H "Content-Type: application/json" \
  -d '{"name": "My Script Key"}'

用户 API Key 继承创建者角色:admin 创建的 Key 拥有管理员权限,普通用户创建的 Key 只有用户级权限。从数据模型看(models.go),API Key 只存储 KeyHash(HMAC-SHA256,uniqueIndex)与 KeyPrefix(前 8 位用于展示),并可选 ExpiresAt 过期时间与 LastUsed 最近使用时间戳,原始 Key 永不落库。创建/列出/撤销 Key 的路由实现位于 core/http/routes/auth.go,撤销后立即失效。

中间件中的凭据解析顺序middleware.go tryAuthenticate)值得关注,它决定了同名凭据的优先级:

  1. session Cookie → 会话校验(Web UI);
  2. Authorization: Bearer <token> → 先尝试作为会话 token,再尝试作为命名 API Key;
  3. x-api-key / xi-api-key 请求头 → 命名 API Key;
  4. token Cookie → 命名 API Key。

会话记录本身在 models.go 中被定义为「会话 token 的 HMAC-SHA256 哈希」(主键),并带过期时间与轮换时间戳 RotatedAt;Cookie 会话还支持会话轮换(MaybeRotateSession)。

Auth API 端点一览

方法 端点 说明 所需认证
GET /api/auth/status 认证状态、当前用户、可用 providers
POST /api/auth/token-login 用用户或 legacy API Key 换取浏览器会话
POST /api/auth/register 用 email 与密码注册
POST /api/auth/login 用 email 与密码登录
GET /api/auth/github/login 开始 GitHub OAuth
GET /api/auth/github/callback GitHub OAuth 回调(内部)
GET /api/auth/oidc/login 开始 OIDC 登录
GET /api/auth/oidc/callback OIDC 回调(内部)
POST /api/auth/logout 结束会话
GET /api/auth/me 当前用户信息
POST /api/auth/api-keys 创建 API Key
GET /api/auth/api-keys 列出当前用户的 API Key
DELETE /api/auth/api-keys/:id 撤销 API Key
GET /api/auth/usage 用户自己的用量统计
GET /api/auth/usage/sources 用户自己按 API Key / 来源的明细
GET /api/auth/admin/users 列出全部用户 管理员
PUT /api/auth/admin/users/:id/role 修改用户角色 管理员
DELETE /api/auth/admin/users/:id 删除用户 管理员
GET /api/auth/admin/usage 全部用户的用量统计 管理员
GET /api/auth/admin/usage/sources 全部用户按 API Key / 来源的明细 管理员
POST /api/auth/admin/invites 创建邀请链接 管理员
GET /api/auth/admin/invites 列出全部邀请 管理员
DELETE /api/auth/admin/invites/:id 撤销未使用的邀请 管理员

全部端点的路由注册集中在 core/http/routes/auth.go,其中管理员组通过 auth.RequireAdmin() 统一挂载。另外该文件还在认证端点上实现了按 IP 的简单限流器rateLimiter,见 auth.go),用于抵御暴力登录尝试。

用量追踪

启用认证后,LocalAI 会自动记录推理端点的按用户 token 用量。用量数据包括:

  • 每次请求的 prompt tokenscompletion tokenstotal tokens
  • 使用的 模型 与被调用的 端点
  • 请求耗时
  • 用于时间序列聚合的 时间戳

查看用量

用量可通过 Web UI 的 Usage 页面(所有已认证用户可见)或 API 查看:

# 查看自己的用量(默认最近 30 天)
curl http://localhost:8080/api/auth/usage?period=month \
  -H "Authorization: Bearer <key>"

# 管理员:查看全部用户的用量
curl http://localhost:8080/api/auth/admin/usage?period=week \
  -H "Authorization: Bearer <admin-key>"

# 管理员:按指定用户过滤
curl "http://localhost:8080/api/auth/admin/usage?period=month&user_id=<user-id>" \
  -H "Authorization: Bearer <admin-key>"

Period 取值:

  • day — 最近 24 小时,按小时分桶
  • week — 最近 7 天,按天分桶
  • month — 最近 30 天,按天分桶(默认)
  • all — 全部时间,按月分桶

响应格式:

{
  "usage": [
    {
      "bucket": "2026-03-18",
      "model": "gpt-4",
      "user_id": "abc-123",
      "user_name": "Alice",
      "prompt_tokens": 1500,
      "completion_tokens": 800,
      "total_tokens": 2300,
      "request_count": 12
    }
  ],
  "totals": {
    "prompt_tokens": 1500,
    "completion_tokens": 800,
    "total_tokens": 2300,
    "request_count": 12
  }
}

用量仪表盘

Web UI 的 Usage 页面提供:

  • 周期选择器 — 在 day / week / month / 全部时间之间切换
  • 汇总卡片 — 总请求数、prompt tokens、completion tokens、total tokens
  • By Model 表格 — 按模型明细,带可视化用量条
  • By User 表格(仅管理员)— 跨所有模型的按用户明细
  • Sources 标签页 — 按 API Key 与来源的明细(见下)

按 API Key 的明细

Usage 页面的 Sources 标签页在同一份数据上提供第三个维度:按 API Key 与请求来源切分的流量。追踪三种来源类别:

  • API key — 使用命名用户 API Key 认证的请求(Authorization: Bearer lai-...x-api-keytoken Cookie)。每个 Key 会显示其标签(写入时快照,因此已撤销的 Key 仍会显示原始名称)。
  • Web UI — 使用浏览器会话 Cookie 认证的请求。
  • Legacy — 使用环境变量配置的 LOCALAI_API_KEY 认证的请求。仅管理员可见。

Sources 标签页对每个已认证用户可见。非管理员只能看到自己的 Key 加上自己的 Web UI 流量(legacy 在服务端被过滤);管理员能看到所有用户的每个 Key。

页面布局包括:

  • 来源混合条(source mix ribbon):三类来源的百分比切分
  • Top-N + Other 堆叠时间图:按 total tokens 取前 7 个来源,其余归入 Other
  • 可搜索、可排序的表格:列出每个 Key 以及 Web UI 与 Legacy 伪行;点击某行可将图表过滤到该来源

端点

方法 路径 认证 说明
GET /api/auth/usage/sources 本人 调用者按来源的明细;不含 legacy
GET /api/auth/admin/usage/sources 管理员 全部用户按来源的明细;支持 user_idapi_key_id 过滤;包含 legacy

两个端点都接受与 /api/auth/usage 相同的 period 参数(dayweekmonthall)。

# 最近一周自己的按来源用量
curl "http://localhost:8080/api/auth/usage/sources?period=week" \
  -H "Authorization: Bearer <key>"

# 管理员:跨全部用户过滤到单个 API Key
curl "http://localhost:8080/api/auth/admin/usage/sources?period=month&api_key_id=<key-id>" \
  -H "Authorization: Bearer <admin-key>"

响应形状:

{
  "buckets": [
    { "bucket": "2026-05-19", "source": "apikey",
      "api_key_id": "uuid", "api_key_name": "ci-runner",
      "total_tokens": 20000, "request_count": 142, "...": "..." },
    { "bucket": "2026-05-19", "source": "web",
      "total_tokens": 300, "request_count": 11, "...": "..." }
  ],
  "totals": {
    "by_source": {
      "apikey": { "tokens": 1234567, "requests": 8420 },
      "web":    { "tokens":   92000, "requests":   211 }
    },
    "by_key": [
      { "api_key_id": "uuid", "api_key_name": "ci-runner",
        "tokens": 2100000, "requests": 8420,
        "last_used": "2026-05-20T12:34:56Z" }
    ],
    "grand_total": { "tokens": 1334777, "requests": 8645 }
  },
  "truncated": false
}

by_key 列表在服务端按 tokens 降序排序,最多返回 200 条。当还有更多 Key 符合条件时,响应会设置 "truncated": true,以便 UI 展示提示。

旧数据迁移

该功能上线前记录的用量行没有 source 字段。启动时 InitDB 会为它们回填:当用户 ID 为合成的 legacy-api-key 时回填为 legacy,其余回填为 web。迁移是幂等的,升级后已有聚合数据依然正确。

从实现上看,用量记录、按来源切分与聚合逻辑封装在 core/http/auth/usage.go,并有 usage_test.go 覆盖查询与聚合行为;请求来源由中间件写入 Echo context(auth_source),见 middleware.go 中的上下文键定义与 middleware.go 对 legacy 来源的设置。

组合认证模式

Legacy API Key 与用户认证系统可以同时启用。两者都配置时:

  1. 先检查用户会话与用户 API Key
  2. 再回退检查 Legacy API Key——匹配时授予 admin 级访问权限
  3. 这为从共享 API Key 平滑迁移到按用户账户提供了路径。

对应 middleware.go 的中间件主流程:第 2 步先尝试用户体系认证(tryAuthenticate),第 3 步在未认证且存在 legacy Key 时用 isValidLegacyKey 回退并构造合成 admin。两种模式都没启用时(!authEnabled && !hasLegacyKeys),请求直接透传。

构建要求

用户认证系统需要 CGO 以支持 SQLite,并通过 auth build tag 启用——Docker 构建默认已包含该 tag。

# 从源码构建并开启 auth 支持
GO_TAGS=auth make build

# 或直接用 go build
go build -tags auth ./...

仓库 MakefileGO_TAGS?= 支持通过环境变量注入 tag,构建命令会将其透传给 go build -tags "$(GO_TAGS)"。默认 Dockerfile 设置了 GO_TAGS="auth",因此所有 Docker 镜像都带 auth 支持。从源码构建时若不带 auth tag,设置 LOCALAI_AUTH=true 不会生效——系统会在无认证状态下运行。

源码中这种「编译期选择」体现在数据库适配层:core/http/auth/db_sqlite.gocore/http/auth/db_nosqlite.go 分别对应启用/禁用 SQLite 的实现,配合 //go:build auth 约束选择编译单元;相关测试覆盖见 db_sqlite_test.gomiddleware_test.go

小结与源码导航

  • 简单共享密钥防护:用 LOCALAI_API_KEY,但注意它等同管理员;
  • 生产级多用户治理:LOCALAI_AUTH=true + PostgreSQL(网络存储必选)+ 按需接入 GitHub OAuth / OIDC + invite 注册模式;
  • 牢记「默认私有、白名单放行」模型,PathWithoutAuth 与 legacy GET 豁免应尽量收窄;
  • 想让用户自助管理密钥与用量,先部署 Web UI 并用 token-login / 会话让账户体系跑通,再推广用户 API Key。

若想深入实现细节,可按以下路径阅读仓库源码:

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.74 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
595
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.63 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
518
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
389