Given a Plug.Conn that went through a Router like this:
get("/foo/:bar", FooController, :get_foo)
For a request like GET /foo/42, I can use conn.request_path to acess the String /foo/42, but is there a way to get the /foo/:bar string that was matched in the Router ?
I’m trying to write a plug that does authentication based on which route was matched.
In my mind, the plug would load a CSV table to know which role is needed to access a given route.(I tried using macro inside the router, but it lacks the lisibility of a CSV table.)
If you have not already explored this, you can write a plug and break up the routes in pipelines within your routes module. Such a plug could set a role to be used by your authentication module within a controller, or even within the route itself – depending on how you have your authentication system setup:
pipeline :auth_user do
plug MyWebApp.Plug.Auth, :user
end
pipeline :auth_employee do
plug MyWeb.Plug.Auth, :employee
end
scope "/", MyWeb do
pipe_through [:browser, :auth_user]
get "/login/user", AuthenticationController, :new
end
scope "/", MyWeb do
pipe_through [:browser, :auth_employee]
get "/login/employee", AuthenticationController, :new
end
So perhaps in your auth plug you would assign the role set within the defined pipelines (:user, :employee).
You could also do this in the controller at the new method level as well. The options are quite limitless
The problem is in my case, I have a “matrix” of roles and endpoint, and there is no “simple” mapping between endpoints and which roles have access to them.
If I followed your example, I would have an explosion of different plug configuration (potentially, a different configuration for each endpoint !!)
pipeline role_1 do
# Endpoints availble only to users with role "role_1"
plug MyApp.Plug.Auth, roles: ["role_1"]
end
pipeline role_2 do
#Endpoints available only to users with role "role_2"
plug MyApp.Plug.auth, roles: ["role_1"]
end
....
pipeline role_1_or_role_2 do
#Endpoints available only to users with role "role1", or, "role_2", but not "role_3"
plug MyApp.Plug.auth, roles: ["role_1", "role_3"]
end
pipeline role_1_or_role_3 do
#Endpoints available only to users with role "role1", or, "role_3", but not "role_2"
plug MyApp.Plug.auth, roles: ["role_1", "role_2"]
end
...
At some point, I used a custom set of get_xxx macros that made it possible to write something like:
It worked, but it clearly lacked the visibility of a table with one row for each endpoint, and one column for each role. (Which is also much easier to reason about with our PM - arguably, our domain and permission model is a bit complex, but that’s for - good - business reason.)
Yes. you should be able to use that in a plug no problem at all. In fact you’re not calling anything from a controller, you’re just passing the controller module name, which expands to an atom.
What I mean is that i’m writing a Plug like this :
defmodule RolePlug do
def call(conn, _) do
# I can get the Router through which the Conn was passed, but I could not find how to get
# the Controller.
route = conn.request_path
|> Phoenix.Router.Resource.build(???????, [])
route.member[:path]
end
end
Hey @phtrivier so did you follow the csv method for role based access to routes as I am also implementing something in this line only. Is there a recent updated solution that you jumped onto since this thread is 2 year old.