* fix:修复权限问题 * fix:修复项目key类型错误问题 * fix:修复rbac权限问题 * fix:修复api密钥未及时失效的问题 * improve:优化渠道调度稳定性 * improve:优化路由 * fix:修复项目预算控制缺陷 * fix:加强限流等安全措施 * feat:添加限流相关字段的前端展示及接口字段 * improve:优化注册时密码要求,只需要字母和数字即可 * feat(setting):添加注册限流设置 * improve:优化前端数字类型转换 * chore:rbac权限放行 --------- Co-authored-by: chengqian <wuchengqian@kkidc.com> Co-authored-by: qian <wuchengqian5@163.com>
110 lines
2.4 KiB
Go
110 lines
2.4 KiB
Go
package billing
|
|
|
|
import (
|
|
"net"
|
|
"strings"
|
|
)
|
|
|
|
// Scope constants
|
|
const (
|
|
ScopeFull = "full"
|
|
ScopeChatOnly = "chat_only"
|
|
ScopeEmbeddingsOnly = "embeddings_only"
|
|
ScopeImagesOnly = "images_only"
|
|
ScopeAudioOnly = "audio_only"
|
|
ScopeReadOnly = "read_only"
|
|
)
|
|
|
|
// CheckScope 检查 API Key scope 是否允许访问指定 relay mode
|
|
func CheckScope(scope string, relayMode string) bool {
|
|
if scope == "" || scope == ScopeFull {
|
|
return true
|
|
}
|
|
|
|
switch scope {
|
|
case ScopeReadOnly:
|
|
// read_only 仅允许 GET /models
|
|
return relayMode == ""
|
|
case ScopeChatOnly, "chat":
|
|
return relayMode == "chat_completions" ||
|
|
relayMode == "completions" ||
|
|
relayMode == "responses" ||
|
|
relayMode == "claude_messages" ||
|
|
relayMode == "gemini_generate_content" ||
|
|
relayMode == "realtime"
|
|
case ScopeEmbeddingsOnly, "embedding":
|
|
return relayMode == "embeddings"
|
|
case ScopeImagesOnly, "image":
|
|
return relayMode == "images_generations" || relayMode == "images_edits"
|
|
case ScopeAudioOnly, "audio":
|
|
return relayMode == "audio" ||
|
|
relayMode == "tts" ||
|
|
relayMode == "stt" ||
|
|
relayMode == "audio_speech" ||
|
|
relayMode == "audio_transcriptions" ||
|
|
relayMode == "audio_translations"
|
|
default:
|
|
// custom scope: 以逗号分隔的模式列表
|
|
allowed := strings.Split(scope, ",")
|
|
for _, a := range allowed {
|
|
if strings.TrimSpace(a) == relayMode {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
}
|
|
|
|
// IsReadOnlyScope 检查 scope 是否为只读
|
|
func IsReadOnlyScope(scope string) bool {
|
|
return scope == ScopeReadOnly
|
|
}
|
|
|
|
// CheckIPWhitelist 检查 IP 白名单
|
|
// whitelist 为逗号分隔的 IP/CIDR 列表,空列表表示不限制
|
|
func CheckIPWhitelist(whitelist string, clientIP string) bool {
|
|
if whitelist == "" {
|
|
return true
|
|
}
|
|
|
|
// 提取 IP(去除端口)
|
|
host, _, err := net.SplitHostPort(clientIP)
|
|
if err != nil {
|
|
// 没有端口,直接使用原始值
|
|
host = clientIP
|
|
}
|
|
// 去除 IPv6 方括号
|
|
host = strings.TrimPrefix(strings.TrimSuffix(host, "]"), "[")
|
|
|
|
parsedIP := net.ParseIP(host)
|
|
if parsedIP == nil {
|
|
return false
|
|
}
|
|
|
|
allowed := strings.Split(whitelist, ",")
|
|
for _, a := range allowed {
|
|
a = strings.TrimSpace(a)
|
|
if a == "" {
|
|
continue
|
|
}
|
|
|
|
// 精确 IP 匹配
|
|
if a == host {
|
|
return true
|
|
}
|
|
|
|
// CIDR 匹配
|
|
if strings.Contains(a, "/") {
|
|
_, cidr, err := net.ParseCIDR(a)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
if cidr.Contains(parsedIP) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|