mirror of
https://github.com/EZ-Api/ez-api.git
synced 2026-01-13 17:47:51 +00:00
feat(auth): implement master key authentication system with child key issuance
Add admin and master authentication layers with JWT support. Replace direct key creation with hierarchical master/child key system. Update database schema to support master accounts with configurable limits and epoch-based key revocation. Add health check endpoint with system status monitoring. BREAKING CHANGE: Removed direct POST /keys endpoint in favor of master-based key issuance through /v1/tokens. Database migration requires dropping old User table and creating Master table with new relationships.
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/ez-api/ez-api/internal/api"
|
||||
"github.com/ez-api/ez-api/internal/config"
|
||||
"github.com/ez-api/ez-api/internal/middleware"
|
||||
"github.com/ez-api/ez-api/internal/model"
|
||||
"github.com/ez-api/ez-api/internal/service"
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -57,7 +58,7 @@ func main() {
|
||||
log.Println("Connected to PostgreSQL successfully")
|
||||
|
||||
// Auto Migrate
|
||||
if err := db.AutoMigrate(&model.User{}, &model.Provider{}, &model.Key{}, &model.Model{}, &model.LogRecord{}); err != nil {
|
||||
if err := db.AutoMigrate(&model.Master{}, &model.Key{}, &model.Provider{}, &model.Model{}, &model.LogRecord{}); err != nil {
|
||||
log.Fatalf("Failed to auto migrate: %v", err)
|
||||
}
|
||||
|
||||
@@ -67,7 +68,17 @@ func main() {
|
||||
logCtx, cancelLogs := context.WithCancel(context.Background())
|
||||
defer cancelLogs()
|
||||
logWriter.Start(logCtx)
|
||||
|
||||
adminService, err := service.NewAdminService()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create admin service: %v", err)
|
||||
}
|
||||
masterService := service.NewMasterService(db)
|
||||
healthService := service.NewHealthCheckService(db, rdb)
|
||||
|
||||
handler := api.NewHandler(db, syncService, logWriter)
|
||||
adminHandler := api.NewAdminHandler(masterService)
|
||||
masterHandler := api.NewMasterHandler(masterService)
|
||||
|
||||
// 4.1 Prime Redis snapshots so DP can start with data
|
||||
if err := syncService.SyncAll(db); err != nil {
|
||||
@@ -77,17 +88,52 @@ func main() {
|
||||
// 5. Setup Gin Router
|
||||
r := gin.Default()
|
||||
|
||||
// CORS Middleware
|
||||
r.Use(func(c *gin.Context) {
|
||||
c.Writer.Header().Set("Access-Control-Allow-Origin", "*") // TODO: Restrict this in production
|
||||
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
|
||||
c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE")
|
||||
|
||||
if c.Request.Method == "OPTIONS" {
|
||||
c.AbortWithStatus(204)
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
})
|
||||
|
||||
// Health Check Endpoint
|
||||
r.GET("/health", func(c *gin.Context) {
|
||||
c.String(http.StatusOK, "OK")
|
||||
status := healthService.Check(c.Request.Context())
|
||||
httpStatus := http.StatusOK
|
||||
if status.Status == "down" {
|
||||
httpStatus = http.StatusServiceUnavailable
|
||||
}
|
||||
c.JSON(httpStatus, status)
|
||||
})
|
||||
|
||||
// API Routes
|
||||
r.POST("/providers", handler.CreateProvider)
|
||||
r.POST("/keys", handler.CreateKey)
|
||||
r.POST("/models", handler.CreateModel)
|
||||
r.GET("/models", handler.ListModels)
|
||||
r.POST("/sync/snapshot", handler.SyncSnapshot)
|
||||
// Admin Routes
|
||||
adminGroup := r.Group("/admin")
|
||||
adminGroup.Use(middleware.AdminAuthMiddleware(adminService))
|
||||
{
|
||||
adminGroup.POST("/masters", adminHandler.CreateMaster)
|
||||
// Other admin routes for managing providers, models, etc.
|
||||
adminGroup.POST("/providers", handler.CreateProvider)
|
||||
adminGroup.POST("/models", handler.CreateModel)
|
||||
adminGroup.GET("/models", handler.ListModels)
|
||||
adminGroup.POST("/sync/snapshot", handler.SyncSnapshot)
|
||||
}
|
||||
|
||||
// Master Routes
|
||||
masterGroup := r.Group("/v1")
|
||||
masterGroup.Use(middleware.MasterAuthMiddleware(masterService))
|
||||
{
|
||||
masterGroup.POST("/tokens", masterHandler.IssueChildKey)
|
||||
}
|
||||
|
||||
// Public/General Routes (if any)
|
||||
r.POST("/logs", handler.IngestLog)
|
||||
|
||||
srv := &http.Server{
|
||||
|
||||
Reference in New Issue
Block a user