chore: establish local platform baseline

This commit is contained in:
Codex Local
2026-08-26 06:41:54 +08:00
commit 29bdf4900f
575 changed files with 95644 additions and 0 deletions
+55
View File
@@ -0,0 +1,55 @@
package httpapi
import (
"errors"
"net/http"
"strings"
"data-terminal-cloud/internal/identity"
)
func BearerAuth(verifier identity.TokenVerifier, next http.Handler) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
rawToken, ok := bearerToken(request.Header.Get("Authorization"))
if !ok {
writer.Header().Set("WWW-Authenticate", "Bearer")
WriteError(writer, request, http.StatusUnauthorized, "AUTHENTICATION_REQUIRED", "请先登录后再访问")
return
}
principal, err := verifier.Verify(request.Context(), rawToken)
if err != nil {
writer.Header().Set("WWW-Authenticate", `Bearer error="invalid_token"`)
WriteError(writer, request, http.StatusUnauthorized, "AUTHENTICATION_INVALID", "登录凭证无效或已经过期")
return
}
next.ServeHTTP(writer, request.WithContext(identity.WithPrincipal(request.Context(), principal)))
})
}
func CurrentUserHandler(repository *identity.Repository) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Set("Cache-Control", "no-store")
principal, ok := identity.PrincipalFromContext(request.Context())
if !ok {
WriteError(writer, request, http.StatusUnauthorized, "AUTHENTICATION_REQUIRED", "请先登录后再访问")
return
}
currentUser, err := repository.CurrentUser(request.Context(), principal)
switch {
case errors.Is(err, identity.ErrAccountNotFound):
WriteError(writer, request, http.StatusForbidden, "RESOURCE_ACCESS_DENIED", "当前账号无权访问该资源")
case err != nil:
WriteError(writer, request, http.StatusInternalServerError, "INTERNAL_ERROR", "服务暂时不可用")
default:
WriteJSON(writer, request, http.StatusOK, currentUser)
}
})
}
func bearerToken(header string) (string, bool) {
parts := strings.Fields(header)
if len(parts) != 2 || !strings.EqualFold(parts[0], "Bearer") || strings.TrimSpace(parts[1]) == "" {
return "", false
}
return parts[1], true
}