Using HTTP Basic Authentication

You want to use PHP to protect parts of your web site with passwords. Instead of
storing the passwords in an external file and letting the web server handle the
authentication, you want the password verification logic to be in a PHP program.

Solution
The $_SERVER[’PHP_AUTH_USER’] and $_SERVER[’PHP_AUTH_PW’] global variables contain
the username and password supplied by the user,if any. To deny access to a
page,send a WWW-Authenticate header identifying the authentication realm as part of
a response with status code 401:

header('WWW-Authenticate: Basic realm="My Website"');
header('HTTP/1.0 401 Unauthorized');
echo "You need to enter a valid username and password.";
exit;

Discussion
When a browser sees a 401 header,it pops up a dialog box for a username and password.
Those authentication credentials (the username and password),if accepted by
the server,are associated with the realm in the WWW-Authenticate header. Code that
checks authentication credentials needs to be executed before any output is sent to
the browser,since it might send headers. For example,you can use a function such
as pc_validate(), shown in Example 8-2.

function pc_validate($user,$pass) {
/* replace with appropriate username and password checking,
such as checking a database */
$users = array('david' => 'fadj&32',
'adam' => '8HEj838');
if (isset($users[$user]) && ($users[$user] == $pass)) {
return true;
} else {
return false;
}
}
if (! pc_validate($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
header('WWW-Authenticate: Basic realm="My Website"');
header('HTTP/1.0 401 Unauthorized');echo "You need to enter a valid username and password.";
exit;
}

Replace the contents of the pc_validate() function with appropriate logic to determine
if a user entered the correct password. You can also change the realm string
from “My Website” and the message that gets printed if a user hits “cancel” in their
browser’s authentication box from “You need to enter a valid username and password.”
HTTP Basic authentication can’t be used if you’re running PHP as a CGI. If you
can’t run PHP as a server module,you can use cookie authentication,discussed in
Recipe 8.10.
Another issue with HTTP Basic authentication is that it provides no simple way for a
user to log out,other then to exit his browser. The PHP online manual has a few suggestions
for log out methods that work with varying degrees of success with different
server and browser combinations at http://www.php.net/features.http-auth.
There is a straightforward way,however,to force a user to log out after a fixed time
interval: include a time calculation in the realm string. Browsers use the same username
and password combination every time they’re asked for credentials in the same
realm. By changing the realm name,the browser is forced to ask the user for new credentials.
For example, this forces a log out every night at midnight:

if (! pc_validate($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW'])) {
$realm = 'My Website for '.date('Y-m-d');
header('WWW-Authenticate: Basic realm="'.$realm.'"');
header('HTTP/1.0 401 Unauthorized');
echo "You need to enter a valid username and password.";
exit;
}

You can also have a user-specific timeout without changing the realm name by storing
the time that a user logs in or accesses a protected page. The pc_validate() function
in Example 8-3 stores login time in a database and forces a log out if it’s been
more than 15 minutes since the user last requested a protected page.

function pc_validate2($user,$pass) {
$safe_user = strtr(addslashes($user),array('_' => '\_', '%' => '\%'));
$r = mysql_query("SELECT password,last_access
FROM users WHERE user LIKE '$safe_user'");
if (mysql_numrows($r) == 1) {
$ob = mysql_fetch_object($r);
if ($ob->password == $pass) {
$now = time();
if (($now - $ob->last_access) > (15 * 60)) {
return false;
} else {
// update the last access time
mysql_query("UPDATE users SET last_access = NOW()
WHERE user LIKE '$safe_user'");
return true;
}
}
} else {
return false;
}
}    

For example:
if (! pc_validate($_SERVER['PHP_AUTH_USER'],$_SERVER['PHP_AUTH_PW'])) {
header('WWW-Authenticate: Basic realm="My Website"');
header('HTTP/1.0 401 Unauthorized');
echo "You need to enter a valid username and password.";
exit;
}

Tags: , ,

Leave a Reply