schrockwell / bodyguard

Simple authorization conventions for Phoenix apps

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

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Please add example for using plugs with fallback controllers

ndarilek opened this issue · comments

Hey, thanks for this library. Currently using it to add authorization to my app, and the documentation has been mostly very clear.

I'm starting to replace my initial simplistic authorization flow with Bodyguard, and am having some issues using the Authorize plug with a fallback controller. First, I have a policy definition like so:

defmodule ScribeWeb.Policy do
  @behaviour Bodyguard.Policy
  alias __MODULE__

  alias Scribe.Auth.User

  def authorize(_, %User{role: :admin}, _), do: true

  def authorize(:new_document, %User{role: :customer}, _), do: true

  def authorize(:new_document, %User{role: :demo}, _), do: true

  def authorize(_, _, _), do: false
end

Next I have this as an administrative-only controller:

defmodule ScribeWeb.AdminUserController do
  use ScribeWeb, :controller

  alias Scribe.Auth
  alias Scribe.Auth.User

  action_fallback ScribeWeb.FallbackController

  plug Bodyguard.Plug.Authorize
  ...
end

And this as my fallback. Note that this throws a warning about function calls that won't match, because I'm trying to debug it:

defmodule ScribeWeb.FallbackController do
  use ScribeWeb, :controller

  def call(conn, params) do
    IO.inspect(params)
    conn
  end

  def call(conn, {:error, :unauthorized}) do
    conn
    |> put_status(:not_found)
    |> put_view(ScribeWeb.ErrorView)
    |> render(:not_found)
  end
end

Unfortunately this doesn't work, My FallbackController is never hit. I'm unclear as to whether my use of the Authorize plug is incompatible with Phoenix fallbacks, if I have to perform checks on each individual action I want to protect, etc. Ideally I'd like to replace my entire authorization flow with a central policy definition, and some smarter return codes like :requires_login if a user isn't authenticated, :requires_demo if a user needs to request a demo to access the specified URL, etc.

Thanks for any help.

You can find a nice example here https://hexdocs.pm/bodyguard/Bodyguard.Plug.Authorize.html

Believe the key bit you need for you case is adding this fallback: ScribeWeb.FallbackController to your plug Bodyguard.Plug.Authorize call

Added example and clarification to the README – thanks!