| > How do I do that in Phoenix ? Assuming you have a `current_user` stored in assigns, I implement basic role access as: def edit(conn, param) when conn.assigns.current_user.role == :admin do
...
end
If that's too long: defguard is_granted(conn, role) when conn.assigns.current_user.role == role
def edit(conn, param) when is_granted(conn, :admin) do
...
end
It also works on LiveViews with guards on handle_event.--- The other way of doing authorization, which IIRC is similar to voters in Symfony, I typically implement with protocols: defprotocol Authz do
def can?(resource, action, user)
end
Then in my Post schema: defmodule MyApp.Blog.Post do
schema "posts" do
# ...
end
defimpl Authz do
def can?(post, :view, user) do
post.public or can?(post, :edit, user)
end
def can?(post, :edit, user) do
post.owner_id == user.id
end
end
end
You may encapsulate in a controller helper like this, although you cannot use it in guards: def can?(conn, resource, action) do
Authz.can?(resource, action, conn.assigns.current_user)
end
Now you can call it to check against any resource whatsoever. If you don't implement it for a resource or for an action, it will crash as expected.I find it requires less boilerplate than the Voter approach in Symfony (but it has been quite some time since I last checked it). No additional abstractions either. The only downside is that it doesn't work annotation/@decorator style (but if you really want it, it should be doable). --- However, my favorite way of doing authz is by scoping the queries. Typically all of my context functions receive either the org, the user, or a "session" data structure with both which I use as the starting point of my queries. Then I complement with Authz.can? style when that's not enough. |
But the best non-business code I like is the one I don't have to code, commit and maintain.
You don't need voters for the example I wrote earlier though, in fact I don't remember the last time I had to write one.
But I think it's more a functional vs OO discussion and we know how those goes ;)