package middleware import ( "net/http" "slices" "strconv" "strings" "github.com/gin-gonic/gin" "laic-backend/cache" "laic-backend/common" "laic-backend/token" ) // AuthMiddleware 鉴权中间件:解析 JWT + Redis 存证校验 + 注入上下文 func AuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { tokenString := c.GetHeader("Authorization") if tokenString == "" { common.FailWithBusiErrorWithHttpStatus(c, http.StatusUnauthorized, common.ErrUnauthorized) return } tokenString = strings.TrimPrefix(tokenString, "Bearer ") if tokenString == "" { common.FailWithBusiErrorWithHttpStatus(c, http.StatusUnauthorized, common.ErrUnauthorized) return } claims, err := token.ParseToken(tokenString) if err != nil { common.FailWithBusiErrorWithHttpStatus(c, http.StatusUnauthorized, common.ErrToken) return } // Redis 存证校验:登出会删除该 key,从而让已签发 token 失效 storeKey := cache.UserTokenKeyOf(claims.UserID, token.GenerateShortID(tokenString)) if !common.HasKey(storeKey) { common.FailWithBusiErrorWithHttpStatus(c, http.StatusUnauthorized, common.SignOutToken) return } roles := claims.Roles if roles == nil { roles = []string{} } isAdmin := slices.Contains(roles, common.RoleAdmin) c.Set("user_id", claims.UserID) c.Set("username", claims.Username) c.Set("roles", roles) c.Set("is_admin", isAdmin) // Casbin 权限校验(admin 与普通用户均按 p/g 策略校验,admin 仅限平台管理职能) if common.CasbinEnforcer != nil { ok, err := common.CasbinEnforcer.Enforce(strconv.FormatInt(claims.UserID, 10), c.Request.URL.Path, c.Request.Method) if err != nil || !ok { common.FailWithBusiErrorWithHttpStatus(c, http.StatusForbidden, common.ErrForbidden) c.Abort() return } } c.Next() } } // AdminMiddleware 仅管理员可访问 func AdminMiddleware() gin.HandlerFunc { return func(c *gin.Context) { if !c.GetBool("is_admin") { common.FailWithBusiErrorWithHttpStatus(c, http.StatusForbidden, common.ErrForbidden) return } c.Next() } }