|
|
-
Creating a CF login system for Oracle:
Note: The Oracle-related material presented here is largely ColdFusion-version independent. However,
please note that most of the ColdFusion code
has been developed and tested on older versions of ColdFusion (4.0 through 6.0).
Consequently, some CFML code snippets may need to be modified to work optimally on more recent versions of the
product.
Creating a login system for Oracle is really quite simple.
Basically you need a login page and an action page that does
the necessary validation against Oracle and sets session variables
with the userid, password and datasource names. Thereafter, on
every secured page you need to check that the user has been
validated. This is best done through a snippet of code that is
cfincluded into each secured template. Finally, you need a logout
template that destroys the user's session. What follows is a
detailed discussion on how to build each of the components
described above.
In the discussion I assume that users are
to be validated against their Oracle userid/password, and
that these have already been created in Oracle.
The first thing is to ensure that session management is switched
on for the application, as this is the only way to maintain
user state between requests. This is best done in your
application.cfm template, since this is executed with
every request:
<!---excerpt from application.cfm---!>
<cfapplication name="YourAppName"
sessionmanagement="Yes"
setclientcookies="Yes">
Here I have assumed that users are not averse to accepting
cookies. If your users are not thus inclined, you'll have to pass
the session tokens through
the URL - but we'll not go through that tedious exercise
here.
The next step is to create the login page. The body of this
page would contain something similar to
following html:
<!---excerpt from login.cfm--->
<form action="login_action.cfm" method="post">
Login:<input type="text" name="uid">
Password:<input type="password" name="pwd">
Datasource:<input type="text" name="dsn">
<input type="button" value="Login" onclick="submit()">
</form>
Just one point here: you could hardcode your datasource name in
your application.cfm file if you prefer.
The action template for login.cfm contains a whole lot of
validation code followed by a simple database query. If all
is well, session variables for the userid, password and DSN are
set. If not, the user is asked to login again:
<!---excerpt from login_action.cfm--->
<cftry>
<cfif IsDefined("form.uid") AND IsDefined("form.pwd") AND
IsDefined("form.dsn")>
<cfif Trim(Len(form.uid)) EQ 0 OR Trim(Len(form.pwd)) EQ 0
OR Trim(Len(form.dsn)) EQ 0>
<cfthrow message="User name, password or datasource blank.">
<cfelse>
<!--- check if the user has basic select privileges --->
<cfquery datasource="#form.dsn#"
username="#form.uid#"
password="#form.pwd#"
maxrows=1
name="check_authorization">
select
count(*)
from
all_tables
</cfquery>
<cflock timeout="15">
<cfset Session.uid = UCase(form.uid)>
<cfset Session.pwd = form.pwd>
<cfset session.dsn=form.dsn>
</cflock>
</cfif>
<cfelseif (NOT IsDefined("Session.uid"))>
<cfthrow message="User not logged in, or session timed out.">
</cfif>
<!---Your code goes here---!>
<cfcatch>
An authorization error has occurred
Message: <cfoutput>#cfcatch.message#</cfoutput>
Please click on the button to login.
<input type="button"
value="Login"
onclick="location.replace('login.cfm')">
</cfcatch>
</cftry>
Several things need elaboration here:
1. The code is enclosed in a cftry block to allow the use of cfcatch to handle exceptions (such as failed login attempts).
2. The first couple of cfifs check that the appropriate form variables are defined, and that they are not blank.
3. If the tests in (2) are passed, a simple query is sent on to Oracle. This query should be against a table or view that the user is expected to have select privileges on. ALL_TABLES is a view that is a part
of the Oracle data dictionary. This view lists all tables to which the user has access, so it is a good candidate. You can read more about this and other
data dictionary views in the Oracle docs, or in my
CFDJ article
on building a database monitor using CF.
4. If the query is successful we set session variables to hold the userid, password and DSN. These will be used in queries on subsequent pages.
5. You then insert whatever code you want in the placeholder that follows the cfif block. This is typically code you want only authorized users to access and execute.
6. Finally, the cfcatch section traps authorization errors and gives the user an opportunity to login again. Note that
you could trap specific database errors using cfcatch. A "how-to" on this
topic can be found here.
Now, how can we maintain user state in subsequent templates? This is
done very simply by cfincluding the following snippet at the
top of all templates
that use the set session variables. These are basically any
templates that access the database.
<!--- inc_session_test.cfm---!>
<cfif NOT IsDefined("session.uid")>
Authorization error: User not logged in or session timed out.
Please click on the button to login.
<input type="button"
value="Login"
onclick="location.replace('login.cfm')">
<cfabort>
</cfif>
This snippet should be included at the top of all password
protected pages, like so:
<!--- protected_template.cfm--->
<cfinclude template="inc_session_test.cfm">
<!---protected code goes here--->
The cfabort guarantees that processing will stop before the protected
code is reached, if the user is not authenticated.
Finally, in our logout template, we simply loop through the session
structure and destroy all set session variables. Here's the relevant
excerpt from logout.cfm:
<!--- from logout.cfm--->
<cfset user=session.uid>
<cfloop collection=#session# item="i">
<cfset StructDelete(session,i)>
</cfloop>
User <cfoutput>#user#</cfoutput> has been logged out of
YourApp.
Please click on the button below if you want to login
again.
<input type="Button"
value=" Login"
onClick ="location.replace('login.cfm')">
Links or buttons to the above template can be placed on
all protected pages from which you want the user to be
able to logout. Upon clicking the link/button the user's
session is destroyed by the above code. In my apps, I usually
pad up the onclick JavaScript to present the user a
"confirm" box before they are redirected to the logout
page. This enhancement will help prevent unintended logouts-
I have noticed that some users tend to click buttons all over the
place without thinking of the consequences!
This brings me to the end of the discussion. I don't claim that
this is the best way of building a login system, and the
code is far from optimal. However, it is offered up here as a
guide to help you build your own.
Back to the top
|