如何在其他路由中使用特定路由的中间件?

huangapple go评论122阅读模式
英文:

How to use a middleware for a specific route, among other ones?

问题

我的简化路由与以下代码类似:

  1. r.Route("/api/v1", func(r chi.Router) {
  2. r.Route("/case", func(r chi.Router) {
  3. // 通用案例 - 适用于所有人
  4. r.Get("/{uuid}", caseGetByUuid)
  5. r.Put("/", casePut)
  6. // 所有案例仅对管理员可用
  7. // r.Use(ensureAdminUser) // ← 这是我遇到错误的地方
  8. r.Get("/", caseGetAll)
  9. })
  10. // 管理员端点
  11. r.Route("/admin", func(r chi.Router) {
  12. // 确保用户是管理员
  13. r.Use(ensureAdminUser)
  14. r.Route("/user", func(r chi.Router) {
  15. r.Route("/token", func(r chi.Router) { // /admin/user/token
  16. r.Get("/", userTokenGetAll)
  17. r.Put("/", userTokenCreate)
  18. r.Delete("/", userTokenDelete)
  19. })
  20. })
  21. })
  22. })

第二个路由 (/admin) 受到一个中间件的限制,如果不满足特定条件,将中断链条。该中间件位于所有路由之前。

我希望在第一个路由 (/case) 中进行类似的过滤,但只针对其中的一个路由(三个路由中的一个)。取消注释 r.Use(ensureAdminUser) 会导致以下错误:

  1. panic: chi: all middlewares must be defined before routes on a mux

我也不能为 /case 创建两个路由。

是否有办法保留 /case 路由并限制根调用的其中一种方法?

如果没有,我将为受限制的情况创建一个替代路由。

英文:

My simplified routing is similar to

  1. r.Route("/api/v1", func(r chi.Router) {
  2. r.Route("/case", func(r chi.Router) {
  3. // generic case - for everyone
  4. r.Get("/{uuid}", caseGetByUuid)
  5. r.Put("/", casePut)
  6. // all cases only available to admins
  7. // r.Use(ensureAdminUser) // ← this is the place I have an error
  8. r.Get("/", caseGetAll)
  9. }
  10. // admin endpoint
  11. r.Route("/admin", func(r chi.Router) {
  12. // ensure that the user is an admin
  13. r.Use(ensureAdminUser)
  14. r.Route("/user", func(r chi.Router) {
  15. r.Route("/token", func(r chi.Router) { // /admin/user/token
  16. r.Get("/", userTokenGetAll)
  17. r.Put("/", userTokenCreate)
  18. r.Delete("/", userTokenDelete)
  19. })
  20. })
  21. })
  22. })

The second route (/admin) is restricted by a middleware that will break the chain if specific constraints are not met. The middleware is placed ahead of all the routes.

I wanted to do similar filtering in the first route (/case), but only for one route (out of the three). Uncommenting r.Use(ensureAdminUser) leads to

  1. panic: chi: all middlewares must be defined before routes on a mux

I cannot have two routes for /case either.

Is there a way to keep the route /case and restrict one of the methods for the root call?

If not I will create an alternative route for the restricted case.

答案1

得分: 2

你可以将中间件和后续的路由包装在它们自己的中(我强调):

>// Group 在当前路由路径上添加一个新的内联路由器,
>// 并为内联路由器创建一个新的中间件栈
>Group(fn func(r Router)) Router

  1. r.Route("/api/v1", func(r chi.Router) {
  2. r.Route("/case", func(r chi.Router) {
  3. // 通用案例 - 适用于所有人
  4. r.Get("/{uuid}", caseGetByUuid)
  5. r.Put("/", casePut)
  6. // 所有案例仅对管理员可用
  7. r.Group(func(r chi.Router) {
  8. r.Use(ensureAdminUser)
  9. r.Get("/", caseGetAll)
  10. })
  11. }
  12. })

这也适用于使用r.Route创建的子路由器。

另一种选择是当中间件仅应用于一个路由时,可以使用r.With来“内联”中间件:

  1. r.Route("/api/v1", func(r chi.Router) {
  2. r.Route("/case", func(r chi.Router) {
  3. // 通用案例 - 适用于所有人
  4. r.Get("/{uuid}", caseGetByUuid)
  5. r.Put("/", casePut)
  6. // 所有案例仅对管理员可用
  7. r.With(ensureAdminUser).Get("/", caseGetAll)
  8. }
  9. })
英文:

You can wrap the middleware and subsequent routes in their own group (emphasis mine):

>// Group adds a new inline-Router along the current routing
>// path, with a fresh middleware stack for the inline-Route.
>Group(fn func(r Router)) Router

  1. r.Route("/api/v1", func(r chi.Router) {
  2. r.Route("/case", func(r chi.Router) {
  3. // generic case - for everyone
  4. r.Get("/{uuid}", caseGetByUuid)
  5. r.Put("/", casePut)
  6. // all cases only available to admins
  7. r.Group(func(r chi.Router) {
  8. r.Use(ensureAdminUser)
  9. r.Get("/", caseGetAll)
  10. })
  11. }
  12. })

It will work also with a sub-router with r.Route.

Another option when a middleware is applied to only one route is r.With which allows you to “inline” the middleware:

  1. r.Route("/api/v1", func(r chi.Router) {
  2. r.Route("/case", func(r chi.Router) {
  3. // generic case - for everyone
  4. r.Get("/{uuid}", caseGetByUuid)
  5. r.Put("/", casePut)
  6. // all cases only available to admins
  7. r.With(ensureAdminUser).Get("/", caseGetAll)
  8. }
  9. })

huangapple
  • 本文由 发表于 2022年3月13日 23:06:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/71458028.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定