Is this a good way to protect routes?

Hi,

I have a project controller and I want to make sure only project creator can access some of the routes so I’ve created a controller plug to check if the current user is project creator. This plug works fine but I would like to know if this is the right way to approach this or is there maybe a better way?

plug :authorize_creator when action in [:edit, :update, :delete]
defp authorize_creator(conn, _opts) do
    current_user = conn.assigns.current_user
    project = Projects.get_project!(conn.params["slug"])

    if current_user.id == project.user_id do
      conn
    else
      conn
      |> put_flash(:error, "You can't access that page.")
      |> redirect(to: Routes.page_path(conn, :index))
      |> halt()
    end
end

Yes I think that is a friendly way to do it. I mean friendly for a user trying to update/delete a resource he is not allowed to. It is likely someone trying to hack the app by typing into the url. Otherwise he shouldn’t being reaching that route.

So showing him a 404 not found page should be ok in my sense.

The brutal way for doing it is to use a Context function that take both the resource id and the author id as parameters. Something like get_user_project!/2.

In your controller edit/update/delete actions

user = conn.assigns.current_user
project = Projects.get_user_project!(user.id, conn.params["slug"])

the Context function will looks like

def get_user_project!(user_id, project_slug) do
 MyRepo.get_by!(Project, slug: project_slug, user_id: user_id)
end

With this you don’t even have to use a plug for authorization. If the current user is not the author of the requested project an exception will be raised and a 404 page will be shown.

2 Likes