Gin + GORM + pure-Go SQLite. Users/auth (JWT), API key management with quotas, proxy gateway with weighted channel failover and health checks, usage/billing ledger, cross-protocol conversion (Anthropic Messages / OpenAI Chat Completions / OpenAI Responses), and channel/model admin API. Channels declare native API formats and auto-convert the rest. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
75 lines
1.7 KiB
Go
75 lines
1.7 KiB
Go
package user
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"openteam/server/internal/pkg/httpx"
|
|
"openteam/server/internal/pkg/jwt"
|
|
"openteam/server/internal/store"
|
|
)
|
|
|
|
const (
|
|
ctxUserKey = "current_user"
|
|
ctxClaimsKey = "current_claims"
|
|
)
|
|
|
|
// Current returns the authenticated user (set by Middleware).
|
|
func Current(c *gin.Context) *store.User {
|
|
if v, ok := c.Get(ctxUserKey); ok {
|
|
if u, ok := v.(*store.User); ok {
|
|
return u
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Claims returns the JWT claims of the current request.
|
|
func Claims(c *gin.Context) *jwt.Claims {
|
|
if v, ok := c.Get(ctxClaimsKey); ok {
|
|
if cl, ok := v.(*jwt.Claims); ok {
|
|
return cl
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Middleware authenticates the management API via an access token.
|
|
func (s *Service) Middleware(secret string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
auth := c.GetHeader("Authorization")
|
|
if !strings.HasPrefix(auth, "Bearer ") {
|
|
httpx.Fail(c, http.StatusUnauthorized, "missing bearer token")
|
|
return
|
|
}
|
|
token := strings.TrimPrefix(auth, "Bearer ")
|
|
claims, err := jwt.Parse(secret, token)
|
|
if err != nil || claims.Type != "access" {
|
|
httpx.Fail(c, http.StatusUnauthorized, "invalid or expired token")
|
|
return
|
|
}
|
|
var u store.User
|
|
if err := s.db.First(&u, claims.UserID).Error; err != nil || u.Status != "active" {
|
|
httpx.Fail(c, http.StatusUnauthorized, "user not found or disabled")
|
|
return
|
|
}
|
|
c.Set(ctxUserKey, &u)
|
|
c.Set(ctxClaimsKey, claims)
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
// RequireAdmin guards admin-only routes.
|
|
func RequireAdmin() gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
u := Current(c)
|
|
if u == nil || u.Role != "admin" {
|
|
httpx.Fail(c, http.StatusForbidden, "admin only")
|
|
return
|
|
}
|
|
c.Next()
|
|
}
|
|
}
|