riverrun / openmaize

No longer maintained - was an Authentication library for Plug-based applications in Elixir
Other
206 stars 30 forks source link

Passing the whole User struct after authorization #39

Closed jaimeiniesta closed 8 years ago

jaimeiniesta commented 8 years ago

After an action has been authorized with:

def action(conn, _), do: authorize_action conn, ["user"], __MODULE__

We get the user as a third param in the actions:

def index(conn, params, user) do

However, we only get some of its data:

IO.inspect user
# %{email: "jaimeiniesta@gmail.com", exp: 1464787171584, id: 1, nbf: 1464779971584, role: "user"}

So we then need to get the whole user from the DB in order to be able to fetch all its data, associations, etc.

    current_user = Repo.get(User, user.id)

Is that the supposed way to do this? Could Openmaize instead pass the whole User instead? Or maybe a %User{} struct with this data, like, including the __struct__: User key?

riverrun commented 8 years ago

The user information depends on the information in the JSON Web Token, which is fairly basic. I want to look into making this more customizable. I'll open a separate issue about customizing this info within the next few days, and I'll provide a link on this thread.

riverrun commented 8 years ago

I've added a configurable item called token_data to openmaize_jwt (this is on the master branch, not in the hex package). At the moment, this is a list of atoms, which refer to entries in the database, but I might decide to use a map or keyword list instead. It would be useful to know what kind of data you would like in the current_user variable.

jaimeiniesta commented 8 years ago

I'm not sure about this. I come from Rails, where we have authentication libraries like Devise, which will set a current_user for you, which is the whole User instance. So you have all its attributes, associations and methods at your disposal.

In the Programming Phoenix book example they do something similar, the plug that assigns the current user takes it from the database:

  def call(conn, repo) do
    user_id = get_session(conn, :user_id)

    cond do
      user = conn.assigns[:current_user] ->
        put_current_user(conn, user)
      user = user_id && repo.get(Rumbl.User, user_id) ->
        put_current_user(conn, user)
      true ->
        assign(conn, :current_user, nil)
    end
  end
riverrun commented 8 years ago

On the Openmaize side, there's no need to call the database, as enough information (for authentication) is contained in the JSON Web Token. If you need to have the complete user struct as current_user, then you can override the default action function in the controller module, calling the database at that point. As this is quite straightforward, I prefer to keep the Openmaize behavior as it is. I think it might be a good idea, though, to add an example action function to the documentation somewhere. If you have any further comment, please let me know.

jaimeiniesta commented 8 years ago

Thanks for the explanation, sounds good to me. Some examples in the documentation would be great, yes. :+1:

riverrun commented 8 years ago

In the openmaize-phoenix example app, there's now an authorize_action_dbcheck function, in the Authorize module, which does a db lookup and adds that to the current_user (this has also been added to the mix generator templates). This function is being used in the UserController module - you can see what has changed in this commit.

jaimeiniesta commented 8 years ago

:+1: