An Introduction To ISAPI - ISAPI Database Example
(Page 3 of 4 )
Before beginning our database application, we need a database to access. I've included a copy of the database I'll be using in this example with the source code for this article. If you like, you can create this database yourself or you can just follow along with this tutorial. The database is a Paradox 7 database named "users.db". It contains the following fields: "User", "Password", "Special Comments", and "Key". All four fields are strings. We must also create an "alias" in the BDE for this database. I named mine "ISAPI_Example". (NOTE: Delphi comes with a tool to assist in creating databases: Database Desktop. Within this application, it’s very easy to create a database and then define the fields for that database).
Like in our previous example, we create our new project from File->New Project->Other...->ISAPI/NSAPI Dynamic Link Library. Our WebModule loads and we can begin altering the application. The simple ISAPI extension we'll make is one that, when called, provides a login form which submits to another action called "PostLogin". After submission, it checks the login information against the database, and if the data matches it outputs the "Special Comments" field for that user. On a successful login, the "key" field of the database will be edited to include a randomly generated number. Two cookies will then be set, one for the "username" value and the other for the "key" value.
This will allow the user to access other areas of the site without having to log back in every time. Our main login form will check for the cookies, and, if they exist and are correct, the user will then be directed to the post-login page. Another function, logoff, will delete the cookies.
Before defining our functions, we should create our TTable component - this will allow for our database access. We create an instance of this component in the WebModule. We then define the properties: Name = UsersDB, DatabaseName = Users (or whatever you named your alias), TableName = users.db, Active = false.
The following actions/functions will be included (as described above):
- Login (Default)
- PostLogin
- Main
- Logoff
The first function, login, is set as follows:
procedure TWebModule1.WebModule1LoginAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
UsersDB.active := true; //Table must be active for use
//This will output the login form
response.content := '<html><head><title>Login</title></head><h3>Login</h3>'
+ '<form name="login" action="' + request.ScriptName + '/postlogin" method="post">'
+ 'Username: <input type="text" name="user"><br>Password: <input type="password" name="password">'
+ '<p><input type="submit" value="Login"></form></html>';
//The following if clause will check if the user is logged in, if so, they'll be
//forwarded to the "main" page. The redirect can override the content from above.
if request.CookieFields.values['user'] <> '' then //Check for user cookie
begin
UsersDB.Filter := '(user = ''' + request.cookiefields.values['user'] + ''')';
UsersDB.Filtered := true;
if UsersDB.fieldbyname('key').asstring = request.CookieFields.values['key'] then
response.sendredirect(request.ScriptName + '/main'); //This will override the content from response.content
end;
UsersDB.Active := false; //Always be sure to stop the database to avoid errors/corruption.
end;We now need to create our login handler, PostLogin. It must first check to see whether the method called is "POST". It must then check the information. The code below accomplishes this task. Upon a successful login, it forwards the user to the "Main" page with some JavaScript. The reason we use JavaScript to forward the user is because if we use a standard request.sendredirect, then the cookies will not be sent/set.
procedure TWebModule1.WebModule1PostLoginAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var authenticated: boolean; //This will hold whether authentication was valid or not
begin
UsersDB.Active := true;
//Default the authenticated value to "not-valid".
authenticated := false;
//Check the method for POST and make sure the values aren't blank...
if (request.method='POST') and (request.ContentFields.values['user'] <> '') and (request.contentfields.values['password'] <> '') then
begin
UsersDB.Filter := '(user = ''' + request.contentfields.values['user'] + ''') and (password = ''' + request.contentfields.values['password'] + ''')';
UsersDB.Filtered := true;
if UsersDB.RecordCount = 1 then
authenticated := true;
end;
//If not authenticated, output an error; if authenticated, send the user to "main" and set the cookies.
if authenticated = false then
response.content := '<html><head><title>Error!</title></head><h3>Error!</h3><hr>There was an error processing your login!</html>'
else
begin
// If valid, set the cookies
with response.cookies.add do
begin
name := 'user';
value := request.contentfields.values['user']
end;
randomize(); //allows for use of the random() function
//Create a random "key" session variable.
UsersDB.edit;
UsersDB.fieldbyname('key').asstring := IntToStr(random(999999));
UsersDB.post;
//Set the "Key" cookie that will be checked against the database
with response.cookies.add do
begin
name := 'key';
value := UsersDB.fieldbyname('key').asstring;
end;
//Forward to the main page
response.content := '<script language="JavaScript">document.location.href="' + request.scriptname + '/main";</script>';
end;
UsersDB.Active := false;
end;The next step is to create the "Main" action. It'll first check the authentication based on the cookies and the "key" value in the database. Then, if the authentication passed, it will output the "Special Comments" field from the database and include a link to "Logoff". Here's our definition for the "Main" action:
procedure TWebModule1.WebModule1MainAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var authenticated: boolean;
begin
//Default our authentication value to false.
authenticated := false;
//Start the database and set the filter to the cookie values. If the database checks
//against the cookies, set authenticated to true. Otherwise send the login page.
UsersDB.Active := true;
UsersDB.filter := '(user = ''' + request.cookiefields.values['user'] + ''') and (key = ''' + request.cookiefields.values['key'] + ''')';
UsersDB.filtered := true;
if UsersDB.recordcount = 1 then
begin
authenticated := true;
end
else
begin
//If not authenticated, send them to the login page.
response.sendredirect('login');
end;
//Send the main page if authenticated properly.
if authenticated = true then
begin
response.content := '<html><head><title>Welcome</title></head><h3>Welcome<hr><strong>Welcome ' + usersdb.fieldbyname('user').asstring + ',</strong><br>'
+ '<i>Special Comments</i><br>' + usersdb.fieldbyname('special comments').asstring + '<p><a href="logoff">Logoff</a></html>';
end;
UsersDB.active := false;
end;And finally, we define the logoff action:
procedure TWebModule1.WebModule1LogoffAction(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
//To delete cookies, set the expiration date to the past.
with response.cookies.add do
begin
name := 'user';
value := '';
expires := Now-1; //Expires Yesterday :)
end;
with response.cookies.add do
begin
name := 'user';
value := '';
expires := Now-1; //Expires Yesterday :)
end;
//Use JavaScript to forward to the login page. Remember - we can't use response.sendredirect because
//the cookies will not register then...
response.content := '<script language="JavaScript">document.location.href="login";</script>';
UsersDB.active := false;
end;This basically provides the entire application. The reason I've provided the source code rather than just outlining it is because you can follow along using the comments in the source code to help you understand what's going on at various points throughout our ISAPI application. To see a working version of this application,
click here. You can login with tue username Guest and password Guest.
Here's how it looked for me:


Next: Conclusion >>
More IIS Articles
More By Raj Bakhru