Files
Agent-System-Backend/internal/server/auth.go
T
weichen 02e2036fc6 Add dual-tier storage (embedded SQLite + optional PostgreSQL)
Details (original message):
Add dual-tier storage (embedded SQLite + optional PostgreSQL), tenant owner scoping, API key auth, versioned dual-dialect migrations, integrity hardening, and batched event persistence
2026-09-30 02:39:50 +00:00

68 lines
1.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package server
import (
"context"
"net/http"
"strings"
"agent-system-backend/internal/store"
)
// ownerCtxKey 携带租户身份(认证中间件注入;未启用认证 = store.OwnerDefault)。
type ownerCtxKey struct{}
// Authenticator 是 API key 认证(阶段 1:user 即租户)。
// Enabled=false(嵌入式档默认,回环本地单用户)时全部请求回落默认租户。
// SSE 的 EventSource 无法带 Authorization 头,允许 ?key= 查询参数兜底。
type Authenticator struct {
st *store.Store
Enabled bool
}
func NewAuthenticator(st *store.Store, enabled bool) *Authenticator {
return &Authenticator{st: st, Enabled: enabled}
}
func (a *Authenticator) Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if a == nil || !a.Enabled {
next.ServeHTTP(w, r.WithContext(withOwner(r, store.OwnerDefault)))
return
}
key := bearerKey(r)
if key == "" {
key = r.URL.Query().Get("key")
}
if key == "" {
http.Error(w, "unauthorized: missing API key (Authorization: Bearer <key>)", http.StatusUnauthorized)
return
}
owner, ok := a.st.AuthOwner(key)
if !ok {
http.Error(w, "unauthorized: invalid or revoked API key", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r.WithContext(withOwner(r, owner)))
})
}
func withOwner(r *http.Request, owner string) context.Context {
return context.WithValue(r.Context(), ownerCtxKey{}, owner)
}
func bearerKey(r *http.Request) string {
h := r.Header.Get("Authorization")
if strings.HasPrefix(h, "Bearer ") {
return strings.TrimSpace(strings.TrimPrefix(h, "Bearer "))
}
return ""
}
// owner 从请求上下文取租户身份(未注入回落默认)。
func (s *Server) owner(r *http.Request) string {
if v, ok := r.Context().Value(ownerCtxKey{}).(string); ok && v != "" {
return v
}
return store.OwnerDefault
}