// Package middleware Gin 中间件:会话鉴权、admin 校验。 package middleware import ( "net/http" "github.com/gin-gonic/gin" "github.com/openteam/server/internal/app" "github.com/openteam/server/internal/pkg/resp" "github.com/openteam/server/internal/store" ) const CtxSessionUser = "session_user" // SessionAuth 会话鉴权:Authorization: Bearer 。 func SessionAuth(a *app.App) gin.HandlerFunc { return func(c *gin.Context) { auth := c.GetHeader("Authorization") if len(auth) < 8 || auth[:7] != "Bearer " { resp.Fail(c, http.StatusUnauthorized, "missing or invalid access token") c.Abort() return } claims, err := a.JWT.Parse(auth[7:]) if err != nil || claims.Subject != "access" { resp.Fail(c, http.StatusUnauthorized, "invalid or expired access token") c.Abort() return } var u store.User if err := a.DB.First(&u, claims.UserID).Error; err != nil { resp.Fail(c, http.StatusUnauthorized, "user not found") c.Abort() return } if u.Status != store.UserStatusActive { resp.Fail(c, http.StatusForbidden, "user account disabled") c.Abort() return } c.Set(CtxSessionUser, &u) c.Next() } } // AdminOnly 仅管理员。 func AdminOnly(c *gin.Context) { u, ok := c.Get(CtxSessionUser) if !ok { resp.Fail(c, http.StatusUnauthorized, "authentication required") c.Abort() return } if u.(*store.User).Role != store.RoleAdmin { resp.Fail(c, http.StatusForbidden, "admin permission required") c.Abort() return } c.Next() } // CORS 开发期放开;生产按配置白名单(PLANNING §8)。 func CORS() gin.HandlerFunc { return func(c *gin.Context) { origin := c.GetHeader("Origin") if origin != "" { c.Header("Access-Control-Allow-Origin", origin) c.Header("Vary", "Origin") c.Header("Access-Control-Allow-Credentials", "true") c.Header("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Requested-With") c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS") } if c.Request.Method == http.MethodOptions { c.AbortWithStatus(http.StatusNoContent) return } c.Next() } }