restructure: console→client-console, add admin-console skeleton, move docs to doc/
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"fission-console/internal/auth"
|
||||
)
|
||||
|
||||
// ctxKeyNS — ключ для K8s namespace пользователя в context.Context.
|
||||
type ctxKeyNS struct{}
|
||||
|
||||
// ctxKeyIdentity — ключ для UserIdentity пользователя в context.Context.
|
||||
type ctxKeyIdentity struct{}
|
||||
|
||||
// authTokenFromRequest извлекает Bearer токен из X-Auth-Token или Authorization заголовка.
|
||||
func authTokenFromRequest(r *http.Request) string {
|
||||
token := strings.TrimSpace(r.Header.Get("X-Auth-Token"))
|
||||
if token != "" {
|
||||
return token
|
||||
}
|
||||
authz := strings.TrimSpace(r.Header.Get("Authorization"))
|
||||
if authz == "" {
|
||||
return ""
|
||||
}
|
||||
const bearerPrefix = "Bearer "
|
||||
if len(authz) >= len(bearerPrefix) && strings.EqualFold(authz[:len(bearerPrefix)], bearerPrefix) {
|
||||
return strings.TrimSpace(authz[len(bearerPrefix):])
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// userNS возвращает namespace пользователя из контекста запроса.
|
||||
func (s *Server) userNS(r *http.Request) string {
|
||||
if ns, ok := r.Context().Value(ctxKeyNS{}).(string); ok && ns != "" {
|
||||
return ns
|
||||
}
|
||||
return s.ns
|
||||
}
|
||||
|
||||
// normalizeEnv приводит название стенда к допустимому значению.
|
||||
func normalizeEnv(env string) string {
|
||||
switch strings.TrimSpace(strings.ToLower(env)) {
|
||||
case "prod", "dev", "test":
|
||||
return strings.TrimSpace(strings.ToLower(env))
|
||||
}
|
||||
return "test"
|
||||
}
|
||||
|
||||
// authMiddleware оборачивает handler аутентификацией.
|
||||
// Токен передаётся в s.authenticator.Authenticate — детали скрыты за интерфейсом.
|
||||
func (s *Server) authMiddleware(h http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var identity auth.UserIdentity
|
||||
|
||||
env := normalizeEnv(r.Header.Get("X-Auth-Env"))
|
||||
|
||||
token := authTokenFromRequest(r)
|
||||
var err error
|
||||
identity, err = s.authenticator.Authenticate(r.Context(), token, env)
|
||||
if err != nil {
|
||||
writeJSONError(w, http.StatusUnauthorized, "unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
ns := auth.NamespaceForSub(identity.Sub)
|
||||
ctx := s.contextWithIdentity(r.Context(), identity)
|
||||
if err := s.nsManager.EnsureUserNS(ctx, ns); err != nil {
|
||||
writeJSONError(w, http.StatusBadGateway, fmt.Sprintf("ensure namespace: %v", err))
|
||||
return
|
||||
}
|
||||
|
||||
h(w, r.WithContext(ctx))
|
||||
}
|
||||
}
|
||||
|
||||
// contextWithIdentity кладёт UserIdentity и вычисленный namespace в контекст.
|
||||
func (s *Server) contextWithIdentity(ctx context.Context, identity auth.UserIdentity) context.Context {
|
||||
ns := auth.NamespaceForSub(identity.Sub)
|
||||
ctx = context.WithValue(ctx, ctxKeyNS{}, ns)
|
||||
ctx = context.WithValue(ctx, ctxKeyIdentity{}, identity)
|
||||
return ctx
|
||||
}
|
||||
Reference in New Issue
Block a user