WhosOnCFC and User Authentication
I am working on the next revision of WhosOnCFC and in this release I am adding simple role-based user authentication. I inserted a new tracked field into the active users array named Roles. As the name implies, this is just a CSV list of roles the current session is authorized for. The roles must be passed to WhosOnCFC on each request so I created a session-scoped struct to hold the user information. Since the code required to log a session out is the same as the code to initialize a session, we kill two birds with one stone in the application file:
<cfset session.userinfo.user="Guest" />
<cfset session.userinfo.roles="" />
</cfif>
The default behavior of WhosOnCFC is to use the user and roles information from the session.userinfo struct and pass it along with the other variables in the thisRequest struct:
thisRequest=structNew();
thisRequest.thisClient=session.sessionid;
thisRequest.thisUser=session.userinfo.user;
thisRequest.Roles=session.userinfo.roles;
thisRequest.Referer=CGI.HTTP_REFERER;
thisRequest.IP=CGI.REMOTE_ADDR;
if(CGI.PATH_INFO is CGI.SCRIPT_NAME){
thisRequest.CurrentPage=CGI.SCRIPT_NAME;
}else{
thisRequest.CurrentPage=CGI.SCRIPT_NAME & CGI.PATH_INFO;
}
thisRequest.QueryString=CGI.QUERY_STRING;
thisRequest.ServerName=CGI.SERVER_NAME;
thisRequest.Prefix="http://";
if(CGI.HTTPS is "on") thisRequest.Prefix="https://";
thisRequest.UserAgent=CGI.HTTP_USER_AGENT;
thisRequest.trackedUser=application.whoson.WhosOnPageTracker(whoson=thisRequest);
if(session.userinfo.user is not thisRequest.trackedUser){
session.userinfo.user=thisRequest.trackedUser;
session.userinfo.roles='';
}
</cfscript>
The code above is accomplishing several different things. First we create the thisRequest struct that we are going to pass to WhosOnCFC for tracking the session. When the WhosOnPageTracker() function is called it is going to return one of two values. If the user is already logged in and has an active session WhosOnPageTracker() will return the user we passed to it in the thisRequest struct, otherwise it is going to return Guest and the user and roles values in the session.userinfo struct will be reset to the default. The only reason WhosOnPageTracker() would return any user other than the one we passed to it would be if there was an existing session, but there had been no activity within the amount of time specified by defaultTimeout defined when the whoson.cfc component was initialized.
It is left utp to you to handle how the user is logged in. Once a user has been authenticated just save the user and the associated roles to the session.userinfo struct. To give you an idea of how this works, here is the login page included with the example application. We build the user query on the fly so no database is required for the example.
<!--- Build our query --->
<cfscript>
myQuery=queryNew("username,password,roles");
queryAddrow(myQuery);
querySetCell(myQuery,"username","admin");
querySetCell(myQuery,"password","admin");
querySetCell(myQuery,"roles","user,admin");
queryAddrow(myQuery);
querySetCell(myQuery,"username","user");
querySetCell(myQuery,"password","user");
querySetCell(myQuery,"roles","user");
</cfscript>
<cfquery name="validateUser" dbtype="query">
SELECT username, password, roles
FROM myQuery
WHERE username='#form.uname#' and password='#form.pass#'
</cfquery>
<cfif validateUser.RecordCount>
<cfscript>
session.userinfo.user=validateUser.username;
session.userinfo.roles=validateUser.roles;
</cfscript>
<cflocation url="/" addToken="false" />
</cfif>
</cfif>
<cfoutput>
<a href="/">HOME</a><br /><br />
<cfif session.userinfo.user is "Guest">
<cfform name="loginForm" action="#CGI.SCRIPT_NAME#" method="post">
User <cfinput type="text" name="uname" required="true" message="Username is required" validateat="onSubmit" /><br />
Pass <cfinput type="text" name="pass" required="true" message="Password is required" validateat="onSubmit" /><br />
<br />
<br />
<input type="submit" value="Login Now!">
</cfform>
<cfelse>
<a href="/?logout">LOGOUT</a>
</cfif>
</cfoutput>
As I said, I tried to keep it simple. Once we have set the user and roles and we have the user logged in, I added in a new function, userIsInRole() which takes a user and a list of roles to check their roles against and will return true or false, depending on whether or not they passed the role check. Currently it does loose role checking, meaning if a user is in at least one of the roles it will return true. I am debating adding in strict role checking where the user would have to be in all the roles before it would return true. As an example, here is how it works:
If you are logged in as an admin, you can read this!<br /><br />
</cfif>
Well, that is about all I have for now. If you would like to play with it a bit you can check out the demo application site at http://whosoncfc.kisdigital.com. I welcome any comments or suggestions.


There are no comments for this entry.
[Add Comment]