5 ms·
As a new Phoenix convert I agree with a lot of these points from my experience too. The functional components make more sense in the majority of cases (and I th
by FinalDestiny 3y ago
As a new Phoenix convert I agree with a lot of these points from my experience too. The functional components make more sense in the majority of cases (and I think the docs point this out) and having the duplicate auth logic with on_mount feels less than ideal.
Hopefully the team will see this and make it even better!
- bobwaycott 3y agoI find a lot of engineers I work with don’t understand on_mount. You shouldn’t have duplicate logic in on_mount—if you do, that code should be in a module. You only have the logic once, but you may call the function twice (though you don’t have to). All your auth logic (and any other bits you need to set while starting up request state) should be a function in a module somewhere that returns expected values. Then, you just care to set these values to Conn and Socket assigns appropriately, keeping in mind that Conns and Sockets aren’t the same—when you have one, you don’t have the other. Thus, on_mount to the rescue: 1. Use Plug pipeline(s) to call your module function to compute and add bits to Conn.assigns (and you can add those values to the session to avoid computing again, if you’d like). 2. Use on_mount to assign_new: 2a. assign_new pulls from Conn.assigns by key for the dead render while you have a Conn. 2b. The fallback function gets that value again when you no longer have a Conn (recompute or pull from session if already there). Your actual logic should only exist in one place. And there are easy strategies you can use to avoid expensive computations if necessary. [Edit]: Not suggesting you don’t understand it, just to be clear. I’ve just experienced a lot of coworkers fighting against, abusing, and misunderstanding Conns, Sockets, and assigns.
- AlchemistCamp 3y agoExactly. Since mix phx.gen.auth handles the authN side, it’s really just authZ that will be idiosyncratic to your application logic. In every authorization system I’ve written in a Phoenix app (which 8 now), I’ve taken this approach above. Make a pipeline of rules that take a conn or socket and authorize or not based on what’s in the assigns. Better yet, at the very top of the pipleline, wrap the conn or socket with an auth struct that holds metadata like authorization status and any redirection to be done. Unwrap that struct into the conn or the socket at the end of the pipeline, where the status is resolved. This way, every request can be default unauthorized and you can apply complex, composable rules for granting permission to take various actions on resources.
- lc-0815 3y agocan you provide sample code of one of your auth you have created, I would like to learn how to code the pipelines as your mention thanks a bunch
- conradfr 3y agoIn other words phx.gen.auth generates a lot of code that may or may not in part suits your authentification needs and Phoenix gives you nothing for Authorization ;) (I am a bit bitter after implementing authentication with Firebase and authorization in a Phoenix app? Maybe ahah).
- AlchemistCamp 3y agoThis a bit too negative of an interpretation. In 100% of the apps where I've used mix phx.gen.auth, the code it's generated has been suitable. In some cases, I've used it in conjunction with a library like Ueberauth for social logins, but it's been strictly superior to older workflows using 3rd party services or frameworks that take over the whole user table. Reaching for something like Firebase or especially Auth0 has added effort in the long run in each project where I've inherited that decision. The typical end-state seems to be a soup of logic split between the 3rd party provider and inside the application. It's more difficult to reason about and more expensive to audit. Nothing is going to do your authZ for you, unless it was made with your business logic in mind. Different apps are going to have radically different needs and there isn't a single best solution for all of them.
- 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.