Coder Social home page Coder Social logo

Comments (8)

zanderxyz avatar zanderxyz commented on June 18, 2024

Sure. In your router.ex you'll see that the Plugs.Veil.UserID is in the list under the :browser pipeline (near the top). If you add Plugs.Veil.User directly underneath that, then this will add the Veil.User struct to conn.assigns[:veil_user]. You should then be able to access the email/other attributes in your controller/views as required.

Example router pipeline:

pipeline :browser do
    plug(:accepts, ["html"])
    plug(:fetch_session)
    plug(:fetch_flash)
    plug(:protect_from_forgery)
    plug(:put_secure_browser_headers)
    plug(PhoenixExampleWeb.Plugs.Veil.UserId)
    plug(PhoenixExampleWeb.Plugs.Veil.User)
end

Alternatively, if you only need the User struct to be loaded for certain specific requests (to avoid the app querying the database every single time), you could add it in the controllers instead. For example, the following controller would assign the veil_user only if the controller function being called was :new or :create.

defmodule YourAppWeb.Controller
  use YourAppWeb, :controller

  plug YourAppWeb.Plugs.Veil.User when action in [:new, :create]

  # ...

Does that help?

from veil.

nickjj avatar nickjj commented on June 18, 2024

I originally tried adding HelloWeb.Plugs.Veil.User to the authenticated pipeline (instead of adding it to browser directly because I figured I would only be able to access this user if they are authenticated).

If I add it to the browser pipeline like you have and then try to output <%= conn.assigns[:veil_user].email %> in a template condition that only happens if a user is loggedin then I get function HelloWeb.SharedView.render/2 is undefined and it points to the line where I'm referencing that conn variable.

It looks like this in the template:

<%= if veil_user_id = @conn.assigns[:veil_user_id] do %>
  <li>
    <a href="#"><%= conn.assigns[:veil_user].email %></a>
  </li>
  <li>
    <a href="<%= session_path(@conn, :delete, @conn.assigns[:session_unique_id]) %>">Sign Out</a>
  </li>
<% else %>
  <li>
    <a href="<%= user_path(@conn, :new) %>">Sign in</a>
  </li>
<% end %>

And this in the router's browser pipeline (just as you have it):

# ...
plug(HelloWeb.Plugs.Veil.User)

from veil.

zanderxyz avatar zanderxyz commented on June 18, 2024

It should work fine in the authenticated pipeline too. I just quickly checked and this works for me. I think the problem is probably that in a template you will need to call @conn.assigns[:veil_user], does that work?

from veil.

zanderxyz avatar zanderxyz commented on June 18, 2024

Also you may not be able to call it as <%= @conn.assigns[:veil_user] %>, as Phoenix won't know how to print the struct. I would recommend writing it like this:

<%= if veil_user = @conn.assigns[:veil_user] do %>
Authenticated as <%= veil_user.email %>
<% end %>

from veil.

nickjj avatar nickjj commented on June 18, 2024

Ok, yep it was a missing @.

But that does lead to another issue (which you may have just addressed).

If I put that pipeline in like this: pipe_through([:browser, HelloWeb.Plugs.Veil.Authenticate, HelloWeb.Plugs.Veil.User]) then I get a nil reference on the email even when logged in. It's also protected by the original <%= if veil_user_id = @conn.assigns[:veil_user_id] do %> condition (see the snippet in the previous comment).

If I drop it into the main :browser pipeline then it all works. I don't quite understand that.

Also, you mentioned:

(to avoid the app querying the database every single time)

At the end of the day, with this plug activated, are you saying we're performing 2 DB lookups per request now? One from step 3 in https://github.com/zanderxyz/veil#security and now again to get the user?

Edit: I do see 2 queries in the debug log output, one for the session and one for the user. Yikes.

from veil.

zanderxyz avatar zanderxyz commented on June 18, 2024

That surprises me too, I don't understand why that would happen. If I take the default Router block and add the Plugs.Veil.User one in like so:

# Default Routes for Veil
  scope "/veil", PhoenixExampleWeb.Veil do
    pipe_through([:browser, PhoenixExampleWeb.Plugs.Veil.User])

    post("/users", UserController, :create)

    get("/users/new", UserController, :new)
    get("/sessions/new/:request_id", SessionController, :create)
    get("/sessions/signout/:session_id", SessionController, :delete)
  end

And then I visit http://localhost:4000/veil/users/new, I see the Authenticated as [email protected] in the top right. Do you not?

And for question two, yes, although they are requests to different tables. The UserId plug calls {:ok, session} <- Veil.get_session(session_unique_id), on row 15, which gets the session from the database. In theory they could be combined into a single request with a join if one needed session plus user for every single future request. Or it could be a single Plug that did the work of both steps.

from veil.

zanderxyz avatar zanderxyz commented on June 18, 2024

Meant to add: I'm not sure which is best but maybe the latter. I could probably refactor it pretty easily.

from veil.

nickjj avatar nickjj commented on June 18, 2024

Oh, I set things up a little different. I attached that plug to an authenticated pipe_through (a set of scoped roles that weren't the default routes for veil).

Feel free to close this issue if you wanted to open a separate issue for potentially refactoring the DB calls.

from veil.

Related Issues (16)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.