On the server, cfc's are not exempt from automatic session creation and cookie management
For a request to have access to session variables, these conditions must be met:
- The client must make a request that gets routed to ColdFusion (i.e. it hits a
cfc
or cfm
, not some static html or js).
- There must be an
Application.cfc
in the same directory or some ancestor directory of the one where the requested cfm
/cfc
is.
- The
Application.cfc
must enable session variables with this.sessionmanagement = true;
When those conditions are met, ColdFusion will associate the request with a session. There are 3 ways this association can me made:
- The client already has valid session cookies and sends them in the request. Your CFML code can read session variables that were created in previous requests, and set new values for future requests to read.
- The client is new, and has no cookies. ColdFusion creates a new set of cookies and a new session scope. Your CFML code can set session variables for future requests to read. The new cookies are automatically sent to the client along with your response.
- The client sends cookies, but they correspond to an expired session. This is handled just like the previous case. New cookies are sent and an empty session scope exists for your CFML to fill.
On the client, ajax requests are not exempt from cookies either
The underlying XMLHttpRequest gets and sets cookies from the same cookie store as all other requests. If the requested URL matches the domain, path, secure flag of a cookie, XMLHttpRequest will send the cookie. And if it gets valid cookies in response, it will add them.
Mostly you just use session variables without thinking about cookies or how they got there
So for your use case, if your login
page is internally routed to login.cfm
, and there's an Application.cfc
nearby, the session scope is ready for you to use as soon as login.cfm
starts. You can do
if(IsDefined("form.username") && IsDefined("form.password")) {
if(...check password [aka the hard part]...) {
session.user = form.username;
location(url="/home");
} else {
location(url="/login");
}
} else {
...print the login form...
}
And your logout
code can StructDelete(session, "user")
Everywhere else, in all your cfc
's and cfm
's, the question of whether the request came from a logged-in user is simple: if the client has previously logged in, and the session hasn't expired, then session.user
exists. Otherwise it doesn't (you will have a session - there is always a session because ColdFusion creates one before running your CFML code - but there will be no user
variable in it until you put one there).
You can set other user-related variables in the login request too (and unset them at logout), like real name, preferences, anything you want to load from a database that will be frequently used and infrequently updated, you can keep in the session scope. Also there's cflogin
which is supposed to help with managing user logins, but it seems pretty unnecessary. (See Why don't people use <CFLOGIN>?)
Your desire to avoid "having to ask every single time" is not really fulfilled, but the "asking" is minimal. The client sends the cookies in every ajax request, which is effectively "asking" for the session to be continued. And it must check every ajax response for the "session timeout" error. And on the server, every request-processing function must begin with a check for existence of a session variable.
But you can use an ajax wrapper on the client to ease the pain.
On the server, you can use an onRequestStart
to provide a common "precheck" to all requests so you don't even need to have if(...no user...) { return "OH NO"; }
at the top of every function.