fix: API Key 前缀调整为 sk-ot-

This commit is contained in:
Sakurasan
2026-08-26 15:57:04 +08:00
parent c78a473e59
commit a45a6e16bd
5 changed files with 9 additions and 9 deletions
+2 -2
View File
@@ -275,8 +275,8 @@ Anthropic /v1/messages ──┘
#### 5.3.3 API Key #### 5.3.3 API Key
- 格式:`sk-ot` + 48 位随机 base62,**创建时仅展示一次**。 - 格式:`sk-ot-` + 48 位随机 base62,**创建时仅展示一次**。
- 存储:仅 SHA-256 哈希 + 展示前缀(如 `sk-otaB3c…`);请求时哈希后查表。 - 存储:仅 SHA-256 哈希 + 展示前缀(如 `sk-ot-aB3c…`);请求时哈希后查表。
- 附加能力:密钥级配额(每日 token / 请求数)、模型白名单、过期时间、启停。 - 附加能力:密钥级配额(每日 token / 请求数)、模型白名单、过期时间、启停。
- 限额检查用 Redis 计数,与用户级限流叠加。 - 限额检查用 Redis 计数,与用户级限流叠加。
+1 -1
View File
@@ -17,7 +17,7 @@
- **限流/配额**(内存计数):密钥级每日请求数 / Token 数配额、用户级每秒速率(`OT_RATELIMIT_USER_RPS`);超限返回 429 - **限流/配额**(内存计数):密钥级每日请求数 / Token 数配额、用户级每秒速率(`OT_RATELIMIT_USER_RPS`);超限返回 429
- **前端**:Dashboard / 管理总览骨架屏加载态 - **前端**:Dashboard / 管理总览骨架屏加载态
- **用户体系**:注册(开放/邀请码可切换,管理后台可改)、登录(JWT access + HttpOnly refresh cookie)、argon2id 密码 - **用户体系**:注册(开放/邀请码可切换,管理后台可改)、登录(JWT access + HttpOnly refresh cookie)、argon2id 密码
- **API Key**:`sk-ot` 48 位 base62,仅存 SHA-256 哈希,明文一次性展示;支持限额/过期/白名单字段 - **API Key**:`sk-ot-` 48 位 base62,仅存 SHA-256 哈希,明文一次性展示;支持限额/过期/白名单字段
- **用量计费**:请求级 `usage_logs` 异步批量落库,按模型价格扣减余额,日粒度预聚合(`usage_daily`) - **用量计费**:请求级 `usage_logs` 异步批量落库,按模型价格扣减余额,日粒度预聚合(`usage_daily`)
- **管理 API**:渠道 CRUD + 连通测试 + 模型导入、模型管理 + 定价 + 渠道绑定、用户管理、全局用量/统计、系统配置 - **管理 API**:渠道 CRUD + 连通测试 + 模型导入、模型管理 + 定价 + 渠道绑定、用户管理、全局用量/统计、系统配置
- **前端**(Vue3 + Tailwind,taste-skill 设计,深色优先) - **前端**(Vue3 + Tailwind,taste-skill 设计,深色优先)
+3 -3
View File
@@ -1,4 +1,4 @@
// Package apikey 生成与管理 API Key:sk-ot + 48 位 base62 随机串。 // Package apikey 生成与管理 API Key:sk-ot- + 48 位 base62 随机串。
// 库中仅存 SHA-256 哈希与展示前缀(PLANNING §4.3.3)。 // 库中仅存 SHA-256 哈希与展示前缀(PLANNING §4.3.3)。
package apikey package apikey
@@ -12,7 +12,7 @@ import (
const ( const (
alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
keyLen = 48 keyLen = 48
prefix = "sk-ot" prefix = "sk-ot-"
) )
// Generate 生成明文 key(仅创建时展示一次)与哈希、前缀。 // Generate 生成明文 key(仅创建时展示一次)与哈希、前缀。
@@ -34,7 +34,7 @@ func Hash(key string) string {
return hex.EncodeToString(sum[:]) return hex.EncodeToString(sum[:])
} }
// Prefix 展示前缀:sk-ot…(前 12 字符) // Prefix 展示前缀:sk-ot-aB3c…(前 12 字符)
func Prefix(key string) string { func Prefix(key string) string {
if len(key) <= 12 { if len(key) <= 12 {
return key return key
+1 -1
View File
@@ -142,7 +142,7 @@ func (g *Gateway) Auth(c *gin.Context) {
key = strings.TrimSpace(c.GetHeader("x-api-key")) key = strings.TrimSpace(c.GetHeader("x-api-key"))
} }
if !apikey.Valid(key) { if !apikey.Valid(key) {
apiError(c, http.StatusUnauthorized, "invalid_api_key", "Invalid API key format. Expected: Authorization: Bearer sk-ot... or x-api-key: sk-ot...") apiError(c, http.StatusUnauthorized, "invalid_api_key", "Invalid API key format. Expected: Authorization: Bearer sk-ot-... or x-api-key: sk-ot-...")
c.Abort() c.Abort()
return return
} }
+2 -2
View File
@@ -79,7 +79,7 @@ const baseURL = `${window.location.origin}/v1`
<div class="space-y-3 p-4 leading-relaxed"> <div class="space-y-3 p-4 leading-relaxed">
<div> <div>
<p class="text-muted"><span class="text-accent">$</span> curl {{ baseURL }}/chat/completions</p> <p class="text-muted"><span class="text-accent">$</span> curl {{ baseURL }}/chat/completions</p>
<p class="text-muted"> -H <span class="text-accent">"Authorization: Bearer sk-ot..."</span> \</p> <p class="text-muted"> -H <span class="text-accent">"Authorization: Bearer sk-ot-..."</span> \</p>
<p class="text-muted"> -d <span class="text-ink">'{"model": "claude-sonnet-5", "messages": [{"role": "user", "content": "你好"}]}'</span></p> <p class="text-muted"> -d <span class="text-ink">'{"model": "claude-sonnet-5", "messages": [{"role": "user", "content": "你好"}]}'</span></p>
</div> </div>
<div class="border-t border-edge pt-3 text-muted"> <div class="border-t border-edge pt-3 text-muted">
@@ -136,7 +136,7 @@ const baseURL = `${window.location.origin}/v1`
</p> </p>
</div> </div>
<div class="card p-5"> <div class="card p-5">
<p class="font-mono text-xs text-muted">sk-ot…</p> <p class="font-mono text-xs text-muted">sk-ot-…</p>
<h3 class="mt-2 text-lg font-semibold">API Key 管理</h3> <h3 class="mt-2 text-lg font-semibold">API Key 管理</h3>
<p class="mt-2 text-sm leading-relaxed text-muted"> <p class="mt-2 text-sm leading-relaxed text-muted">
密钥仅存哈希,支持配额、过期与模型白名单,创建时一次性展示。 密钥仅存哈希,支持配额、过期与模型白名单,创建时一次性展示。