I have been building a user authentication system with user roles. I am now at a point where I am starting to really dig into routing based on roles and I am running into problems. I have built it with the idea that a role is required. I am now finding that this has some pitfalls and I want to know if I should have done it another way. What are the benefits to have every user have a role compared to only having a role if needed otherwise assume not special user?
In my understanding users are dispatched by roles. So there would be for example admins
, superadmins
and default users
. For the last ones, the role could be called client
, member
, or even user
or default
. There should not be many roles, or at least not much more than there are user interfaces. This way the routing will be easier I think.
For example we can things like:
# somewhere in a router to allow only `admins` and `superadmins`
pipeline :admin do
plug :browser
plug :ensure_role, [:admin, :superadmin]
end
# Then in some Controller
plug(:ensure_role, :superadmin when action in [:delete])
If for example superadmins
had their own UI, and so for for admins
, it would be even more straightforward to do the routing,
For routes allowed to all authenticated user, I just use some plug like require_user
, for ones that need not to be authenticated I have require_guest
.
One issue I encountered was when I tried to assign multiple roles to the same user. That will complicate things a lot. So I try to avoid that and create roles that fully qualified users.
I’m a Phoenix/Elixir noob, but I did a PHP app using Role Based Access Control (https://auth0.com/docs/authorization/concepts/rbac), in which every user has one or more roles, and every role has one or more permissions. Each permission usually would map to a route. Hopefully that helps.
When i can do the job without permissions’ complexity, I really prefer that. But It’s certain that for some kind of requirements, just roles won’t be sufficient to handle authorization. I guess what I call “role” should rather be called “user type”?
You can define two pipelines, one requiring the user to be authenticated (with role), the other without such requirement.
pipeline :api do
plug(:accepts, ["json"])
end
pipeline :jwt_authenticated do
plug(Guardian.AuthPipeline)
end
scope "/api", AtmWeb do
pipe_through(:api)
post("/sign_up", UserController, :create)
post("/sign_in", UserController, :sign_in)
resources("/categories", CategoryController, except: [:new, :edit]) # no role required
...
end
scope "/api", AtmWeb do
pipe_through([:api, :jwt_authenticated])
resources("/records", RecordController, except: [:new, :edit]) # role is needed and verified by controller.
...
end