lazaronixon / authentication-zero

An authentication system generator for Rails applications.
MIT License
1.62k stars 53 forks source link

Current without autenticated #85

Closed johannesschobel closed 1 year ago

johannesschobel commented 1 year ago

Dear @lazaronixon ,

thanks again for this wonderful gem. I have been playing around a bit, and i really like it. Following up on #81 , i have another question - maybe you could help and point me into the right direction?

In my application layout, i have a navbar that shows the email-address of the currently logged in user (i.e., Current.user.email). This navbar is present in all views.

Normal pages (i.e., everything related to imprint, about, contact, ...) should be accessible for "guest" users, therefore i have the skip_before_action :authenticate in my PagesController. However, when calling the pages#contact route, the Current.user.email is not shown, because Current.user is not present. This is, because the authenticate method is not called (i.e., i use the skip_before_action)

How can i still get the Current.user, if the user has been logged in before?

Thank you very much for helping me out. All the best, Johannes

lazaronixon commented 1 year ago

3 options… 1 - add a type to the user and customize the flow 2 - if it’s just the email set it as a cookie. 3 - create a guest model, and add a guest attribute to Current.rb, load it from cookies in a before_action…

johannesschobel commented 1 year ago

Dear @lazaronixon ,

i am not sure, if i explained it correctly. Actually, i don't want some kind of Guest user (that can be "converted" into a real user, if the user signs up; as described in #75 ).

I want:

I guess, we could have another method, like get_session in the application_controller in order to address this issue:

# ApplicationController

before_action :get_session

def get_session
  return unless session_record = Session.find_by_id(cookies.signed[:session_token])
  Current.session = session_record
end

This way, the Current.user would work (if the user is logged in). What do you think about this solution?

All the best, Johannes

walterdavis commented 1 year ago

I think you could figure out if the same user is looking at two different URLs, but not which user is. That is separate and distinct from your authentication system, which is where current_user usually comes from, and has the responsibility for working out who you are dealing with, based on a shared secret like a username/password combo.

Everyone who interacts with a Web site (not Rails, I mean just any Web site served by any HTTP server) has a session. Rails helpfully exposes that server-side mechanism to you in the controller method session. You can write any key you want into that on one request and read it back out on another. By that key, you can identify an anonymous user from one page to another. You can't know anything about them that you didn't put into that session yourself. And if they move to a different device, or restart their computer, or even wait around long enough before returning, you cannot know that they are a returning user.

https://guides.rubyonrails.org/v7.1.0/action_controller_overview.html#session

The next step up from a session is a cookie. Those come in two flavors: temporary and permanent*. You have to set any values to them in your application, and again, Rails makes that pretty simple to do within a controller method. If you set a "permanent" cookie in one request/response loop, you can read it on the next, and be reasonably certain you have the same visitor (or at least their browser on a single device) between those two visits. This value will survive a restart of the browser or machine, but will not travel between devices, or even different browsers on the same device. The user can also erase this value at their whim, as it is stored on their computer. There's only ~56K of space in a cookie (may be more, haven't actually looked at the spec in a long time) so usually what you stash there is a key, and then any larger data you want to access about the cookie's owner is kept in your database, identified by that key.

https://api.rubyonrails.org/classes/ActionDispatch/Cookies.html

The CurrentAttributes mechanism does not do anything to keep track of the user for you. What it allows you to do is create cross-channels between the layers of a Rails application, such that your controllers (which are at the front line and have direct access to the Web server's session/cookie apparatus) can note the "current" information in a place where the models (which do not have any direct connection to an individual request) can read that and use it within their methods. All it does is give you a tidy way to refer to request-level information without passing that argument along in every method signature. It's still up to your application to put whatever information you want to be available at other layers of your application in there in the first place.

Most importantly: CurrentAttributes only sets these values for the duration of a single request/response loop. Anything you put in there on one page visit is gone after your server replies to that visit, and your application is responsible for setting it again during the next interaction.

https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html

Walter

*Nothing can be set to last forever, but you can give it a significant time to live, up to 20 years. Temporary cookies are similar to sessions in terms of how your application interacts with them. They differ only in where the data is stored.

On Oct 5, 2023, at 2:36 AM, Johannes Schobel @.***> wrote:

Dear @lazaronixon ,

i am not sure, if i explained it correctly. Actually, i don't want some kind of Guest user (that can be "converted" into a real user, if the user signs up; as described in #75 ).

I want:

• to make a controller accessible for everyone (i.e., logged in users, as well as users that are not currently logged in) • still get the Current.user, if the user has been logged in (before he moved to the page, i.e., if a cookie is set) I guess, we could have another method, like get_session in the application_controller in order to address this issue:

ApplicationController

before_action :get_session

def get_session

return unless session_record = Session.find_by_id(cookies.signed[:session_token])

Current.session = session_record end This way, the Current.user would work (if the user is logged in). What do you think about this solution?

All the best, Johannes

— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.

johannesschobel commented 1 year ago

Dear @walterdavis ,

thank you very much for your extensive explanation and answer on this topic. I think, having such a set_session method, as described above, solves my issue.

All the best, Johannes

kwhandy commented 8 months ago

im surprised that it's not just me realize this issue @johannesschobel

when we work with another auth gem(read: devise) we can add <% if user_signed_in? %> tag(cmiiw) to the navbar section, but i've just notice that this gem basically built based on 37signals's HEY influence

then why this important? if you put bit more attention, you'll notice that HEY has 2 domains, www.hey.com ONLY FOR MARKETING and app.hey.com ONLY FOR MAIN SERVICE

with these 2 purpose, we know that authentication on app.hey.com trying to ISOLATE ENTIRE APP FROM PUBLIC EXPOSE rather than what rails programmer usually do

so if anyone plan to do something like in e-commerce site case, i suggest to add new line on main app controller to set session which can help to check if user already logged in or not