package middleware import ( "net/http" "strings" "github.com/freefire/jiang13-bbs/service" "github.com/gin-gonic/gin" ) // AuthMiddleware 认证中间件 type AuthMiddleware struct { auth *service.AuthService } func NewAuthMiddleware(auth *service.AuthService) *AuthMiddleware { return &AuthMiddleware{auth: auth} } // OptionalAuth 可选登录:解析 token,失败不阻断 func (m *AuthMiddleware) OptionalAuth() gin.HandlerFunc { return func(c *gin.Context) { user, ok := m.parseToken(c) if ok { c.Set("user", user) } c.Next() } } // RequireAuth 必须登录 func (m *AuthMiddleware) RequireAuth() gin.HandlerFunc { return func(c *gin.Context) { user, ok := m.parseToken(c) if !ok { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) return } if user.Banned { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "账号已被封禁"}) return } c.Set("user", user) c.Next() } } // RequireAdmin 必须管理员 func (m *AuthMiddleware) RequireAdmin() gin.HandlerFunc { return func(c *gin.Context) { user, ok := m.parseToken(c) if !ok { c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "未登录"}) return } if user.Role != service.RoleAdmin { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "需要管理员权限"}) return } c.Set("user", user) c.Next() } } // parseToken 解析并校验 token: // 1. 优先从 HttpOnly cookie 读取,回退 Authorization header // 2. 校验 JWT 签名和过期 // 3. 查 DB 实时校验 token_version 和 banned 状态 func (m *AuthMiddleware) parseToken(c *gin.Context) (*service.UserClaims, bool) { tokenStr, err := c.Cookie(service.CookieName) if err != nil || tokenStr == "" { auth := c.GetHeader("Authorization") if auth == "" { return nil, false } tokenStr = strings.TrimPrefix(auth, "Bearer ") if tokenStr == auth { return nil, false } } claims, err := m.auth.ParseToken(tokenStr) if err != nil { return nil, false } // 实时校验:token_version 匹配 + 未封禁(防止旧 JWT 在封禁/改密码后仍有效) if _, err := m.auth.ValidateClaims(claims); err != nil { return nil, false } return claims, true } // CurrentUser 从 context 获取当前用户 func CurrentUser(c *gin.Context) *service.UserClaims { if v, ok := c.Get("user"); ok { if u, ok := v.(*service.UserClaims); ok { return u } } return nil }