4 ms·
> This a bit too negative of an interpretation. Yes :) > 3rd party services or frameworks that take over the whole user table. I've never used a Framework wh
by conradfr 3y ago
> This a bit too negative of an interpretation.
Yes :)
> 3rd party services or frameworks that take over the whole user table.
I've never used a Framework when the auth library can't just use your user schema/entity.
I will never agree that using a generator and committing files I didn't write is better DX than using a library and its documentation (which will be easily updatable). It's also kind of limited in scope. Authentication is more than that. Like, JWTs for example.
To each their own.
> Nothing is going to do your authZ for you
The business logic no, the rest yes.
How do I limit a controller or an action for admin users in Symfony ? #[IsGranted('ROLE_ADMIN')], or for a specific user? #[IsGranted('edit', 'post')], done. And the auth/auth are available anywhere in the framework.
How do I do that in Phoenix ? Pull Bodyguard, write a bunch of "with", plugs, or scope with additional code I have to write and maintain.
- josevalim 3y ago> 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.
- conradfr 3y agoThat's sensible ways of doing things obviously. The can? approach is very similar to the Canada lib IIRC. I'll probably try some of those. 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 ;)
- josevalim 3y agoI can see how #[IsGranted(role)] would work without voters but how would #[IsGranted(post, view)] work without voters? Would it dispatch to the post object? If so, then it is pretty much the same as protocols, yeah. Follow up question: do you think the above would be helpful as a short-guide on Phoenix?
- conradfr 3y agoYes you're probably right about the voter, I've probably mixed it up with the automatic parameter conversion for routing. I've done too much Phoenix lately I forgot the rest ;) About the guide I don't know, maybe a blog post yeah, but there is libs that do all that, maybe there's even too many of them. They are fine but lack the cohesiveness you get with something integrated in a framework.