GoFiber同基础路由分组配置不同中间件遇权限拦截问题求助
GoFiber同基础路由组的中间件冲突解决方案
问题场景
在GoFiber框架中,为共享基础路由/的两个路由组配置不同中间件:
- 公开路由组:无需认证,包含
/、/register、/login等接口 - 认证路由组:需启用
AuthRequired中间件,包含/auth/me等接口
但访问公开路由/时,触发了认证中间件并返回401错误(提示认证头缺失),希望保留原基础路由配置,解决该冲突。
原路由代码
func GetRouter() *fiber.App { app := fiber.New() public_group := app.Group("/") public_group.Get("/", func(c *fiber.Ctx) error { return c.SendString("Hello, World 👋!") }) public_group.Post("/register", handlers.RegisterUser) public_group.Post("/login", handlers.AuthenticateUser) // ... auth_group := app.Group("/", middleware.AuthRequired) auth_group.Get("/auth/me", handlers.GetUser) auth_group.Put("/auth/me", handlers.UpdateUser) auth_group.Post("/auth/me/password", handlers.UpdatePassword) // ... }
服务器错误日志
auth middleware engaged [ 2023-12-18 16:22:41 ] GET /v0 | 127.0.0.1 - ✗ Authorization header does not exist Response: 200 [took 337.709µs] { "message": "authorization header required to access this endpoint", "status": 401 }
AuthRequired中间件代码
package middleware import ( responses "backend/models/api/responses" "backend/utils" "fmt" fiber "github.com/gofiber/fiber/v2" ) func AuthRequired(c *fiber.Ctx) error { fmt.Println("auth middleware engaged") auth_header := c.Get("Authorization") if auth_header == "" { return c.JSON(responses.BaseResponse{ Status: 401, Message: "authorization header required to access this endpoint", }) } if _, err := utils.ValidateJWT(auth_header); err != nil { return c.JSON(responses.BaseResponse{ Status: 401, Message: "invalid authorization header", }) } return c.Next() }
问题原因
GoFiber的路由组中间件采用前缀匹配规则,当创建auth_group := app.Group("/", middleware.AuthRequired)时,该中间件会作用于所有以/为前缀的请求(即所有请求),包括公开路由的/、/register等。即使公开路由先注册,请求进来时仍会触发认证组的中间件,导致公开路由被错误拦截。
解决方案
以下两种方案无需修改原有路由路径,即可解决冲突:
方案1:给认证路由单独绑定中间件
放弃使用带中间件的根路由组,直接为每个认证接口单独添加AuthRequired中间件,确保中间件仅作用于指定认证路由,不影响公开路由:
func GetRouter() *fiber.App { app := fiber.New() public_group := app.Group("/") public_group.Get("/", func(c *fiber.Ctx) error { return c.SendString("Hello, World 👋!") }) public_group.Post("/register", handlers.RegisterUser) public_group.Post("/login", handlers.AuthenticateUser) // ... // 直接为认证路由添加中间件,不使用根路由组 app.Get("/auth/me", middleware.AuthRequired, handlers.GetUser) app.Put("/auth/me", middleware.AuthRequired, handlers.UpdateUser) app.Post("/auth/me/password", middleware.AuthRequired, handlers.UpdatePassword) // ... return app }
方案2:在中间件中排除公开路由
修改AuthRequired中间件,判断当前请求路径是否属于公开路径,若是则跳过认证逻辑:
func AuthRequired(c *fiber.Ctx) error { // 定义所有公开路径 publicPaths := map[string]bool{ "/": true, "/register": true, "/login": true, // 可添加其他公开路径 } // 匹配到公开路径则直接放行 if publicPaths[c.Path()] { return c.Next() } fmt.Println("auth middleware engaged") auth_header := c.Get("Authorization") if auth_header == "" { return c.JSON(responses.BaseResponse{ Status: 401, Message: "authorization header required to access this endpoint", }) } if _, err := utils.ValidateJWT(auth_header); err != nil { return c.JSON(responses.BaseResponse{ Status: 401, Message: "invalid authorization header", }) } return c.Next() }
说明
方案1更简洁,适合认证路由数量不多的场景;方案2适合需要批量管理公开路径的场景,两种方案都能保留原有路由结构,无需修改基础路由。
内容的提问来源于stack exchange,提问作者esskayesss
相关产品推荐
相关产品推荐

