schrockwell / bodyguard

Simple authorization conventions for Phoenix apps

Home Page:https://hexdocs.pm/bodyguard/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Bodyguard.Plug.Authorize default action to Phoenix action_name(conn)?

archseer opened this issue · comments

Could we technically make the action always default to action_name(conn)? https://hexdocs.pm/phoenix/Phoenix.Controller.html#action_name/1

That way it would be a smart default that we wouldn't need to then manually specify everywhere.

Can you tell me a little bit more about how you're using the Authorize plug - is it in a Phoenix controller? Just trying to get an idea where the repetition lies.

It's in a Phoenix Controller, and our Bodyguard action always matches the Phoenix Controller action. That way we need to specify in every controller:

plug(
    Bodyguard.Plug.Authorize,
    policy: App.PostPolicy,
    action: &current_action/1, # Phoenix.Controller.current_action/1
    user: &get_current_user/1
)

this way we'd be able to skip the action parameter.

I'm probably going to define a macro that will expand to the above though:

authorize App.PostPolicy

# expands to

plug(
    Bodyguard.Plug.Authorize,
    policy: App.PostPolicy,
    action: &current_action/1,
    user: &App.get_current_user/1
)

I was going to recommend the macro as a quick solution, but it sounds like you're on top of it.

I'd like to avoid the Phoenix dependency in Bodyguard, so I probably wouldn't make it the default option - at least not directly. Instead I'd consider providing a config options so the user can specify default options for the plug, e.g.

config :bodyguard, Bodyguard.Plug.Authorize,
  defaults: [
    action: {Phoenix.Controller, :current_action},
    user: {App, :get_current_user}
  ]

Yeah I guess that makes sense, the default wouldn't work with plain Plug. Using the config to specify it project-wide would be great I think.

By the way, you should probably add a mention of Bodyguard.Plug.Authorize to the main README! It's very useful and seems to be around since 1.x, but we haven't been using it until now because it wasn't mentioned anywhere specifically (and I didn't check the Modules list on hex). Same goes for Bodyguard.Action possibly.

To sidetrack a bit, action and user parameters support a function, but params doesn't. Would be good to support a function there too because then I could do something like this:

# loads a post and assigns it to conn.assigns.post
plug :load_post when action in [:show, :update, :delete]

plug(
    Bodyguard.Plug.Authorize,
    policy: App.PostPolicy,
    action: &current_action/1,
    user: &App.get_current_user/1,
    params: fn conn -> conn.assigns.post end # pass the loaded Post struct to the policy
)

By the way, you should probably add a mention of Bodyguard.Plug.Authorize to the main README

Yeah, good call - I'll make a new issue for that. I think I got so caught up making things nice for Phoenix contexts that I left out the folks would still like to easily authorize at the web layer.

Bodyguard.Action was a kernel of an idea but I haven't really taken it anywhere and am considering soft-deprecating it so I don't want to push it too hard right now. I'd be curious if you are actually using it and how it's working out for you.

To sidetrack a bit, action and user parameters support a function, but params doesn't.

Ah, yeah that would be nice. Will fire up an issue.

Although since you're using functions for every argument, you may as well consider defining a function plug instead.

plug :authorize

def authorize(conn, _) do
  Bodyguard.permit!(App.PostPolicy, current_action(conn), App.get_current_user(conn), conn.assigns.post)
end

Since all the other issues have been opened now, I'll close this one

Thanks for the helpful discussion!