I want to set my app up to prevent multiple simultaneous logins by the same user. What strategies are people using? Is it worth going to database session storage just for this? martin
On Aug 17, 2006, at 2:56 AM, Martin DeMello wrote:> I want to set my app up to prevent multiple simultaneous logins by the > same user. What strategies are people using? Is it worth going to > database session storage just for this?Your definition of "multiple simultaneous" logins is needed to give some concrete direction, but I''ll take a stab at the two most common scenarios. When a user logs in, then opens another login page in the same browser or another browser or even from a second computer, and logs in again, which behavior do you want to happen: a) the second login is rejected, leaving the first login the sole active session, or b) the first login is abandoned, and the second login becomes the sole active session. A user login session, regardless of where it is stored, should have, among other things, a timestamp element that indicates when the login was started or last refreshed, an expiration time, and an ID unique to that login session that has to be supplied with each refresh attempt. To acheive (a), you compare the login time to the expiration time. If the original login is still active (i.e. no logout), and the expiration has not passed, you have to assume the session is active and you simply reject the second login attempt. The session ID is not changed, and continues to be used. To acheive (b), you allow the login, and change the session ID. This automatically nullifies the first login because that ID will no longer be valid for session refreshes. The downside of (a) is that if a session is dropped for any reason (modem connection, client computer crash, drop in database availability) then the user is hosed until the expiration time is passed. That user will not be able to log back in. That generally has a big ugly factor to it. There are downsides to (b) too, but in most applications, they''re less ugly than (a) from the user''s perspective, so (b) tends to be the more common approach. Choosing one depends on why you need to prevent "multiple logins." As far as a database goes, I''ve only ever done it this way as the session management rode along with other user management features at the same time anyway. And, I''m not a fan of cookie based session management. Just feels too iffy. (could be irrational, but there it is). -- greg willits
Martin DeMello wrote:> I want to set my app up to prevent multiple simultaneous logins by the > same user. What strategies are people using? Is it worth going to > database session storage just for this?I personaly use simple cookie based, after each request generate new auth_key, write it to both cookie and database. -- Posted via http://www.ruby-forum.com/.
On 8/17/06, Greg Willits <lists@gregwillits.ws> wrote:> > a) the second login is rejected, leaving the first login the sole > active session, or > b) the first login is abandoned, and the second login becomes the > sole active session.Definitely (b), with the AIM-inspired addition of a "invalidate earlier login/ cancel current login attempt" popup.> A user login session, regardless of where it is stored, should have, > among other things, a timestamp element that indicates when the login > was started or last refreshed, an expiration time, and an ID unique > to that login session that has to be supplied with each refresh attempt.[...]> To acheive (b), you allow the login, and change the session ID. This > automatically nullifies the first login because that ID will no > longer be valid for session refreshes.Yes, this is what I want to do (with a timed ajax call to automatically log out if the session goes invalid), what I''m searching for is the best strategy to associate a user with a session. The only thing I could think of was to move session storage to the db, so that all instances of the webapp have guaranteed access to the same session store and can look up a session for a given userid; I just want to see what other people have come up with so I can consider all the available options. martin
On Aug 17, 2006, at 3:48 AM, Martin DeMello wrote:> On 8/17/06, Greg Willits <lists@gregwillits.ws> wrote: >> >> a) the second login is rejected, leaving the first login the sole >> active session, or >> b) the first login is abandoned, and the second login becomes the >> sole active session. > > Definitely (b), with the AIM-inspired addition of a "invalidate > earlier login/ cancel current login attempt" popup. > >> A user login session, regardless of where it is stored, should have, >> among other things, a timestamp element that indicates when the login >> was started or last refreshed, an expiration time, and an ID unique >> to that login session that has to be supplied with each refresh >> attempt. > [...] >> To acheive (b), you allow the login, and change the session ID. This >> automatically nullifies the first login because that ID will no >> longer be valid for session refreshes. > > Yes, this is what I want to do (with a timed ajax call to > automatically log out if the session goes invalid),I don''t think a timed call to recontact the db to logout is usually necessary. Anytime a refresh is requested, the time delta between the last refresh and the max allowed elapsed time is tested.> what I''m searching for is the best strategy to associate a user > with a session."Best" is probably relative to the level security you''re after and the degree of session hijacking sophistication your app might be subject to, but the common approach is to validate authentication credentials (un/pw or better), then create a sessionID that is stamped on the user''s profile record and passed back to the app. The sessionID is propagated page to page / task to task (I''m not super up on all the AJAX stuff yet) by way of form value (GET or POST) and/or by cookie. As each server side page/task is processed it passes that ID back into the authentication routine to refresh the session. A refresh validates the sessionID (a simple query that just looks for that ID) then verifies the expiration status, then updates the session refresh time stamp on the user''s record. You can get tricky and change the sessionID with every page which reduces hijacking risk, but it has a nasty side effect of breaking the browser back button. So, it''s usually only suitable for controller environments. I tend to have the session data in the user''s record (due to the way I manage authorization permissions) rather than keeping a separate session table. (The latter being better for unknown user sessions).> The only thing I could think of was to move session storage to the db,As opposed to keeping the session info in a cookie or something? Yes, as you suspect, it has to be centralized, and a db is the most practical. An in memory storage of session data is possible if your app has a known ceiling of users that can be accommodated in RAM (e.g. small intranet app).> so that all instances of the webapp have guaranteed access to the > same session > store and can look up a session for a given userid; I just want to see > what other people have come up with so I can consider all the > available options.My descriptions might be vague (teetering on the brink of sleep), so if you need something more explicit, just ask. -- gw
On 8/17/06, Greg Willits <lists@gregwillits.ws> wrote:> > My descriptions might be vague (teetering on the brink of sleep), so > if you need something more explicit, just ask.Thnaks - that''s given me enough to get started with, but I''ll almost definitely have some questions later on. martin
ive done something similar, but i am not invalidating logins, so i''m not 100% sure this would work, but here goes... i have a session model Online and a user model User. class Online < ActiveRecord::Base belongs_to :user set_table_name "sessions" end class User < ActiveRecord::Base # note, no has_one :session here, it''s not needed ... end running rake db:sessions:create will generate the following migration file for sessions: class AddSessions < ActiveRecord::Migration def self.up create_table :sessions do |t| t.column :session_id, :string t.column :data, :text t.column :updated_at, :datetime end add_index :sessions, :session_id end def self.down drop_table :sessions end end when a user logs in, you''ll want to update the sessions with the user id. session.model.user_id = @current_user.id i use this method to keep track of who''s logged in. it''s dirty and not entirely accurate. it would better to call it ''who currently has a session'', but users don''t necessarily understand the idea of sessions, so i just call it ''who''s logged in''. from this point on it''s all assumptions as I haven''t implemented anything like this, but it would be my best guess. when they attempt to login at another workstation, you can check first if a session exists for that user via Online.find_by_user_id(@current_user.id) and if a record is found then you can assume they are already logged in somewhere else and remove the previous session data (possibly copying the stored data from the session before removal) if they want to continue to login at their current workstation. i''m not too sure about how this would affect the previous logged in session. my assumption would be that any attempts to continue to use the app would require them to login again, ie, there''s a check for a current session. hope this helps. On 8/17/06, Martin DeMello <martindemello@gmail.com> wrote:> On 8/17/06, Greg Willits <lists@gregwillits.ws> wrote: > > > > My descriptions might be vague (teetering on the brink of sleep), so > > if you need something more explicit, just ask. > > Thnaks - that''s given me enough to get started with, but I''ll almost > definitely have some questions later on. > > martin > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
On 8/17/06, Chris Hall <christopher.k.hall@gmail.com> wrote:> > and if a record is found then you can assume they are already logged > in somewhere else and remove the previous session data (possibly > copying the stored data from the session before removal) if they want > to continue to login at their current workstation.Now that is a great idea! Hadn''t thought beyond simply discarding the old session, but you''re right, it''d be a pleasant surprise to the user if selected session data was magically remembered. martin