I have an Angular 4 SPA (single page application) being served by a server that has ColdFusion 11 on it. I'm using, via AJAX calls, many functions contained in .CFC files on that ColdFusion server.
I want the following to happen:
The user goes to my Angular 4 app's page (myapp.mydomain.com) and will be redirected to the login screen (myapp.mydomain.com/login) wherein they will enter their username and password. The Angular 4 app will then call a .CFC on the server to validate their login info. The .CFC will return a "yes" or "no" validating the info. Then the Angular 4 app redirects them to myapp.mydomain.com/home (or wherever I want them to go).
At the same time, I want ColdFusion to create a new session for this user -- so that, if the session times out, or the user logs off, any further calls to any other .CFCs will be rejected.
AND if the ColdFusion session times out, I also want the Angular 4 app to notice this and redirect the user to the /login route.
Basically I need to secure both the client-side (using an Auth-Guard-style service in Angular 4, which I know how to do) and the server-side (using ColdFusion 11 Session Management, which I do not know how to do), and I need them to communicate constantly about the authorization status of both, without having to ask every single time whether or not the session is still valid. (Can the Angular 4 app somehow read the ColdFusion session cookies?)
How do I get these two things to cooperate with each other like that? Or is my ignorance of ColdFusion session-management blinding me to a far better solution that I haven't thought of yet?
Any suggestions are appreciated. Thanks!
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:
cfc
or cfm
, not some static html or js). Application.cfc
in the same directory or some ancestor directory of the one where the requested cfm
/cfc
is.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:
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.