-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🚀 [Feature]: Get Route Name/Path inside Middlewares #2195
Comments
Hi, so you are suggesting that we somehow figure out the next route before it gets to this one? I.e. we would have to go through all declared routes and match them with the current url which would be quite unperformant. Would be all very unperformant, currently we check one route after the other in the sequence as it was registered additionally with a few tricks The result of the routes that match could then contain multiple routes, as each middleware has a path and there is no distinction between these and the end handlers. I could only imagine to provide a functionality which is executed outside the internal process and finds out the routes, so that not every request and every user of the framework has to be exposed to the overhead. |
Hi @ReneWerner87 thanks for the explanation, yeah I was imagining that was a performance problem to implement that and also the logic to figure out the route is not simple. Probably I'll do it in another way, I saw that routes are exposed in |
Is it a method like access path and HandlerName? Similar to ctx.HandlerName or ctx.Path? |
If you get it working, let us know maybe this is important for others too Otherwise we have to look again and try to extend the framework |
why not use ctx.Route().Name to get Having understood the problem, can we provide ctx.HandlerName instead of ctx.Route().Name, similar to Hertz's processing logic. I think handler name and route name are the same refer to https://github.com/cloudwego/hertz/blob/develop/pkg/app/context.go#L634 |
Currently I've created kind of a router manager, after the app starts it register all routes names and methods. type Manager interface{
Add(Route)
Get(name, method string) Route
SetPermissions(name, method string, permissions []string)
}
type Route struct{
Name string
Method string
Permissions string
}
func register(app *fiber.App) {
for _, routes := range app.Stack() {
for _, route := range routes {
Manager.Add(Route{Name: route.Name, Method: route.Method})
}
}
} So then I could use that manager like: package main
import (
"fmt"
"github.com/gofiber/fiber/v2"
)
func main() {
app := fiber.New()
// app.Use(logger.New())
// app.Use(cors.New())
app.Use(func(c *fiber.Ctx) error {
fmt.Printf("%+v\n", c.Route().Name) // Prints ""
err := c.Next()
fmt.Printf("%+v\n", c.Route().Name) // Prints "Ping"
return err
})
app.Get("/ping", Ping).Name("Ping")
register(app)
app.Listen(":3000")
}
func Ping(c *fiber.Ctx) error {
route := Manager().Get(c.Route().Name, c.Route().Method)
// Now here I could get the route permissions using route.Permissions and check if user has the permissions.
return c.SendString("Pong!")
} Of course it's not the best approach since inside every route has a boilerplate code, would be nice to have the information of the currently route being called inside middleware so I could put the logic there. |
Maybe we could rethink the app stack logic to v3? @ReneWerner87 @li-jin-gou |
The Hertz's
So for example if we implement the same logic as Hertz's it'll return the handler function name not the actual name defined by user: app.Get("/ping", Ping).Name("Pong") // It will return `main.Ping` not `Pong` Actually the problem is that we don't know the route name before reaching it (as I tested). So in a middleware when we call Just question, is it possible to get the last handler in the chain ? Maybe in that way we could get the actual c.Route().Name? |
I accidentally closed it, still need a better way to get the route name... The workaround I mentioned earlier creates a lot of boilerplate code. Ideally, it would be nice to have the current route name inside the middleware, so that way I only have to worry about one piece of code, not many parts. |
Hi |
We can also develop a feature for v2, but this must be optional and unlike now, could check all routes for the request url In v3 it should be possible in any case, since you can then exchange your router there |
Hello, I would like to share my solution to this problem. I developed a utility that indexes your routes, and creates a fiber-like router that can be used in middleware to get the original route. This solution is a crutch and needs to be improved, but it can be temporarily used until version 3 is released. |
@utherbit Interesting approach, kind of encapsulate the fiber.App. I thought something like that but was a loot of trouble implementing it. So I decided to create the manager... Just one thing, in go we avoid snake case.
|
Hi @mirusky, You can achieve the functionality you're looking for by structuring your middleware so that you are defining permissions directly within the route handler functions. Here's an example: // in a route handler func
api := app.Group(“/api”)
apiRoutes.TodoRoute(api.Group("/todos"))
// ...
func TodoRoute(route fiber.Router) {
route.Get("", authz.RequirePermissions([]string{"todos:read"}), controllers.GetTodos)
route.Get("/:id", authz.RequirePermissions([]string{"todos:read"}), controllers.GetTodo)
route.Post("", authz.RequirePermissions([]string{"todos:create"}), controllers.CreateTodo)
route.Patch("/:id", authz.RequirePermissions([]string{"todos:update"}), controllers.UpdateTodo)
route.Delete("/:id", authz.RequirePermissions([]string{"todos:delete"}), controllers.DeleteTodo)
} By defining permissions within each route handler, you ensure that permissions are enforced at the granular level of each route. Additionally, you could apply a Role check to routes or even groups of routes, example: // admin group
adminRoutes := app.Group("/admin")
adminRoutes.Use(authz.RequireRole("admin")) These approaches allows for a flexible and maintainable way to manage permissions for your routes. Let me know if you need further assistance! |
Feature Description
Expose the route name inside middleware before reach the end handler / last handler in the stack.
Additional Context (optional)
Currently I'm trying to implement a RBAC system, each route has a name defined like "resource.action" eg:
user.create
,user.read
...And the idea is provide an API where user can change the necessary permissions for each route. Like: the route called
user.create
is necessary to be haveadmin
oruser:create
oruser:*
permission.So the Middleware will check the current route name and validate if the logged user has the appropriate permissions.
Some time ago I had seen a similar issue, but I remember that it was mentioned that the way the stack is built would have to be modified. I didn't found the Issue to put it here...
EDIT:
Related Issues #1334 #923
Code Snippet (optional)
Checklist:
The text was updated successfully, but these errors were encountered: