Checking for Authentication

Helo again guys!
Another questions from me :smiley:

How I can restrict some function/routes only for authenticated user?
In django, I can do this easily by putting a decorator on top of function. Like this one :

@login_required
def post_new(request):
    # do stuff here... only for logged in user

I’m using openmaize lib to do my auth job, and its docs doesnt cover any of this issue.

Second question, how I can restrict some functions so that only the author (assuming this is some kind of blogging app) that can only edit his own post? In Ruby maybe something like this (CMIIW) :

def edit
    if @post.user_id != current_user.id
      flash[:notice] = 'Access denied as you are not owner of this Post'
      redirect_to root_path
    end
end

Thank you in advance for any help you can provide :slight_smile:
Cheers!

One way is to use plugs and pipelines. You define a pipeline on your router (possibly :login_required). Inside that pipeline, you add a plug that verifies the authentication mechanism and bail (with 401 or redirects) if no session or authorization header provided.

Edit to add: after that, you can use the pipeline on your scope. For example:

pipeline :login_required do
  # your plugs
end

scope "/", MyApp do
  pipe_through [:browser]
  # public routes
end

scope "/", MyApp do
  pipe_through [:browser, :login_required]
  # protected routes.
  # yes, you can have multiple scopes with the same route.
end

You can see as an example guardian’s docs on using pipelines. I don’t know if guardian plays well with openmaize though. Basically you need something along the lines of Guardian.Plug.VerifySession or Guardian.Plug.VerifyHeader (depends on your authentication mechanism) and Guardian.Plug.EnsureAuthenticated.

For the second one, I think it would be quite straightforward if the user_id is in the post body and you have your current_user detail on session or token. If the POSTed data does not contain user_id, you might need to fetch the post from the DB first.

1 Like

Following this example you can do the following on your controller

import MyApp.Authorize
plug :user_check when action in [:index, :show]
plug :id_check when action in [:edit, :update, :delete]
1 Like

This solved my first issue :smiley:
Thank you so much @cassiogodinho!

This solved my 2nd issue! Thanks for the clue. This is how I do it (I dont know if this is the best way or not, but it works for me. If you know a better way, please let me know) :

  def edit(conn, %{"id" => id}) do
    note = Repo.get!(Note, id)
    current_user = conn.assigns.current_user
    if current_user.id != current_user.id do
      conn
      |> put_flash(:error, "Cannot edit!.")
      |> redirect(to: note_path(conn, :index))
    else
      changeset = Note.changeset(note)
      render(conn, "edit.html", note: note, changeset: changeset)
    end
  end

@bobbypriambodo Thank you mas bro! :smiley:

The plug :id_check when action in [:edit, :update, :delete] was supposed to solve the second issue because this is what the plug is doing.

  def id_check(%Plug.Conn{params: %{"id" => id}, assigns: %{current_user:
     %{id: current_id}}} = conn, _opts) do
    if id == to_string(current_id), do: conn,
     else: auth_error conn, "You are not authorized to view this page", user_path(conn, :index)
  end

Basicly the same you are doing on your action :slight_smile:

1 Like

Wow… Ok, another clue! Thanks @cassiogodinho :smiley:

Anytime, mas :smiley:

1 Like