feat(keys): role-based gateway keys with admin management UI and per-user model scope

This commit is contained in:
root
2026-08-09 10:01:40 +08:00
parent dec03238dd
commit 3408c9cb1f
10 changed files with 901 additions and 82 deletions

View File

@ -121,4 +121,17 @@ func (c *Config) ApplyDefaults() error {
// RuntimeConfig is the persisted web-UI editable slice (sources added/edited).
type RuntimeConfig struct {
Sources []Source `json:"sources"`
Keys []GWKey `json:"keys,omitempty"`
}
// GWKey is a gateway API key persisted in the runtime store. Role is "admin"
// (full management) or "user" (sees only its own key); Models is the allowed
// model whitelist (nil/empty = all models).
type GWKey struct {
Key string `json:"key"`
Role string `json:"role"`
Name string `json:"name,omitempty"`
Models []string `json:"models,omitempty"`
Note string `json:"note,omitempty"`
CreatedAt int64 `json:"created_at,omitempty"`
}

View File

@ -82,4 +82,59 @@ func (s *Store) persistLocked() error {
return err
}
return os.WriteFile(s.path, b, 0644)
}
// ListKeys returns the persisted gateway keys.
func (s *Store) ListKeys() []GWKey {
s.mu.Lock()
defer s.mu.Unlock()
out := make([]GWKey, len(s.data.Keys))
copy(out, s.data.Keys)
return out
}
// KeyByValue looks up a gateway key record by its secret value.
func (s *Store) KeyByValue(key string) (GWKey, bool) {
s.mu.Lock()
defer s.mu.Unlock()
for _, k := range s.data.Keys {
if k.Key == key {
return k, true
}
}
return GWKey{}, false
}
// SaveKey upserts a gateway key record and persists.
func (s *Store) SaveKey(k GWKey) error {
s.mu.Lock()
defer s.mu.Unlock()
for i := range s.data.Keys {
if s.data.Keys[i].Key == k.Key {
s.data.Keys[i] = k
return s.persistLocked()
}
}
s.data.Keys = append(s.data.Keys, k)
return s.persistLocked()
}
// DeleteKey removes a gateway key record and persists.
func (s *Store) DeleteKey(key string) (bool, error) {
s.mu.Lock()
defer s.mu.Unlock()
kept := s.data.Keys[:0]
removed := false
for _, k := range s.data.Keys {
if k.Key == key {
removed = true
continue
}
kept = append(kept, k)
}
if !removed {
return false, nil
}
s.data.Keys = kept
return true, s.persistLocked()
}