Mark asks a question which I think touches on a basic misunderstanding many people have with ColdFusion and sessions:
I am developing an AJAX RSS feed reader for a portal. I've read several proposed methods of handling sessions, but I don't any address my specific need. In order for the client script to retrieve external feeds I have setup a proxy which simply checks whether it is given a valid URL, it grabs the feed and caches it for a minute so that common feeds don't spawn external GETs more than once a minute. Also, If users leave their portal page open, the client will update the feeds every few minutes.
What I don't want is the portal session timeout to be affected by the feeds being retrieved via the proxy, so I put it in its own subfolder with its own Application.cfm. For some measure of security, I want to require that the client has a cookie with a valid, unexpired session. In order to check this cross-application (proxy->portal) I'm using this in Application.cfm:
<cfset a = ArrayNew(1) />
<cfset sessionClass = a.getClass().forName('coldfusion.runtime.SessionScope') />
<cfset sess = StructNew() />
<cfset sess.expired = sessionClass.getMethod('expired', a) />
<cfset tracker = createObject("java","coldfusion.runtime.SessionTracker")>
<cfset sessions = tracker.getSessionCollection('PORTAL')>
<cfset expired = sess.expired.invoke(sessions['PORTAL_'&PORTAL_Session], a)>Now I should be able to check whether expired is true/false, right? ..Nope. Expired only seems to change when the timeout has been reached, apparently it is not set to true when the user clicks logout.
So first off - it is critical you understand that - out of the box - there is no way for you end a user's session. Just because a user clicked "Logout", it does not end his session. I assume your logout code does something like this:
<cfset structDelete(session, "loggedin")>
While this removes data from the session, and may remove the only key you ever set, this did nothing to end the session. The user still has a session and will continue to have one until timed out by the server.
You may be able to find an API in ColdFusion to truly kill the session, but it isn't officially supported. I like to play around with the undocumented APIs too, but I always recommend against this. You have no guarantee it will work.
So obviously there are multiple other ways you can solve this. I think the cookie approach is best. In your main application, I'd simply set a cookie called "LASTHIT". On every request, set it to now.
In your sub application, see if LASTHIT was set more than 20 minutes ago. If so, consider the request invalid.
Archived Comments
What if you structDelete session.sessionID? I haven't done it but wouldn't that make the session irretrievable?
That's probably horrible practice though.
In my session.user object, I have a function called isLoggedIn() which returns true/false. I also have a logout() function that flips the true to false and the Application.cfc or Application.cfm has a "bouncer" that is constantly checking isLoggedIn() - if it returns false, then bye bye - cflocated.
Oh, the additional point I forgot to make. I don't kill the session, I just re-init the object via session.user's init() function.
Ray - correct me if I'm wrong, but CF Enterprise offers another dimension to ending sessions if you use J2EE sessions. It *should* kill the session when the browser is closed.
Cheers,
Davo
Not to rip on CF (it's my livelyhood and all) but what CF *should* do and what it *does* do are two very different things sometimes. From my understanding, when the browser is closed, the J2EE session is effectively 'orphaned' but doesn't actually get destroyed until the timeout is reached.
@David/Davo: My understanding is that J2EE doesn't kill the session when the browser is closed. It just makes sure that you can't go back to the previous session upon returning to the site. The session will time out naturally.
btw, I don't think J2EE sessions is limited to CF Enterprise.
That was my experience Todd, and at least now I know it wasn't something I forgot to set in the Admin. That would be a nice feature for CF 9 :-)
Davo
For what it is worth, and I apologize for being very slightly off-topic: I usually just nuke the CFID and CFTOKEN cookies - which doesn't expire the session as such, it orphans it much the same way that "closing the browser" does. If the user makes a request after "Logout", the application generates a new CFID and CFTOKEN, as well as a brand-spankin' new session scope.
Side note: It would be very nice if CF provided a way to recycle/expire a session through code. Free up some resources immediately rather than wait 20 minutes.
@Goyuix, I used to the same until I took a drink from the J2EE session koolaid. You don't have to set the CFIDE/CFTOKEN cookies anymore when you use the J2EE sessions.
"What if you structDelete session.sessionID? I haven't done it but wouldn't that make the session irretrievable?"
If you do this CF won't create another session.sessionID until you close the browser and open a new one (or, I assume, until the session expires). It has no effect at all if you're using J2EE sessions.