Files
ai-gateway-go/internal/apikey/apikey.go
T
superidou 5759c1862e AI Gateway Go 0.10.0 源码快照 + 旗舰版需求规划报告
M0-M7 已完成:核心网关(身份/RBAC/TOTP/OIDC/SAML/Provider/配额/路由/内容策略/审计/定价)+ 资源市场(MCP/Skills/数字员工)。
含 22 个 PostgreSQL 迁移、管理端/门户端前端源码、OpenAPI 契约、部署 compose。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-12 11:45:54 +08:00

76 lines
1.8 KiB
Go

package apikey
import (
"context"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"errors"
"strings"
"time"
)
var (
ErrInvalid = errors.New("invalid API key")
ErrStore = errors.New("API key store unavailable")
)
type Record struct {
ID string
TenantID *string
Name string
KeyPrefix string
KeyHash []byte
Scopes []string
Enabled bool
RequestsPerMinute int
MonthlyRequestQuota int64
MonthlyTokenQuota int64
ExpiresAt *time.Time
LastUsedAt *time.Time
CreatedAt time.Time
}
type Principal struct {
APIKeyID string `json:"api_key_id"`
TenantID *string `json:"tenant_id,omitempty"`
Scopes []string `json:"scopes"`
RequestsPerMinute int `json:"requests_per_minute"`
MonthlyRequestQuota int64 `json:"monthly_request_quota"`
MonthlyTokenQuota int64 `json:"monthly_token_quota"`
}
func Generate() (secret, prefix string, hash []byte, err error) {
random := make([]byte, 32)
if _, err = rand.Read(random); err != nil {
return "", "", nil, err
}
secret = "gw_" + base64.RawURLEncoding.EncodeToString(random)
prefix = secret[:16]
digest := sha256.Sum256([]byte(secret))
return secret, prefix, digest[:], nil
}
func Digest(secret string) ([]byte, string) {
digest := sha256.Sum256([]byte(strings.TrimSpace(secret)))
return digest[:], hex.EncodeToString(digest[:])
}
func HasScope(scopes []string, required string) bool {
for _, scope := range scopes {
if scope == "*" || scope == required {
return true
}
}
return false
}
type KeyAuthenticator interface {
Authenticate(context.Context, string) error
}
type PrincipalAuthenticator interface {
AuthenticatePrincipal(context.Context, string) (Principal, error)
}