php 基于表单密码验证与HTTP验证用法
PHP 的 HTTP 认证机制仅在 PHP 以 Apache 模块方式运行时才有效,因此该功能不适用于 CGI 版本。在 Apache 模块的 PHP 脚本中,可以用 header() 函数来向客户端浏览器发送“Authentication Required”信息,使其弹出一个用户名/密码输入窗口。当用户输入用户名和密码后,包含有 URL 的 PHP 脚本将会加上 预定义变量 PHP_AUTH_USER , PHP_AUTH_PW 和 AUTH_TYPE 被再次调用,这三个变量分别被设定为用户名,密码和认证类型。预定义变量保存在 $_SERVER 或者 $HTTP_SERVER_VARS 数组中。支持“Basic”和“Digest”(自 PHP 5.1.0 起)认证方法。请参阅 header() 函数以获取更多信息。
PHP 版本问题: Autoglobals 全局变量,包括 $_SERVER 等,自 PHP 4.1.0 起有效, $HTTP_SERVER_VARS 从 PHP 3 开始有效。
以下是在页面上易做图客户端认证的脚本范例:
例子 34-1. Basic HTTP 认证范例
<?php教程
if (!isset( $_SERVER [ PHP_AUTH_USER ])) {
header ( WWW-Authenticate: Basic realm="My Realm" );
header ( HTTP/1.0 401 Unauthorized );
echo Text to send if user hits Cancel button ;
exit;
} else {
echo "<p>Hello { $_SERVER [ PHP_AUTH_USER ]} .</p>" ;
echo "<p>You entered { $_SERVER [ PHP_AUTH_PW ]} as your password.</p>" ;
}
?>
例子 34-2. Digest HTTP 认证范例
本例演示怎样实现一个简单的 Digest HTTP 认证脚本。更多信息请参考 RFC 2617 。
<?php
$realm = Restricted area ;
//user => password
$users = array( admin => mypass , guest => guest );
if (!isset( $_SERVER [ PHP_AUTH_DIGEST ])) {
header ( HTTP/1.1 401 Unauthorized );
header ( WWW-Authenticate: Digest realm=" . $realm .
" qop="auth" nonce=" . uniqid (). " opaque=" . md5 ( $realm ). " );
die( Text to send if user hits Cancel button );
}
// 易做图ize the PHP_AUTH_DIGEST variable
preg_match ( /username="(?P<username>.*)",s*realm="(?P<realm>.*)",s*nonce="(?P<nonce>.*)",s*uri="(?P<uri>.*)",s*response="(?P<response>.*)",s*opaque="(?P<opaque>.*)",s*qop=(?P<qop>.*),s*nc=(?P<nc>.*),s*cnonce="(?P<cnonce>.*)"/ , $_SERVER [ PHP_AUTH_DIGEST ], $digest );
if (!isset( $users [ $digest [ username ]]))
die( Username not valid! );
// generate the valid response
$A1 = md5 ( $digest [ username ] . : . $realm . : . $users [ $digest [ username ]]);
$A2 = md5 ( $_SERVER [ REQUEST_METHOD ]. : . $digest [ uri ]);
$valid_response = md5 ( $A1 . : . $digest [ nonce ]. : . $digest [ nc ]. : . $digest [ cnonce ]. : . $digest [ qop ]. : . $A2 );
if ( $digest [ response ] != $valid_response )
die( Wrong Credentials! );
// ok, valid username & password
echo Your are logged in as: . $digest [ username ];
?>
兼容性问题: 在编写 HTTP 标头代码时请格外小心。为了对所有的客户端保证兼容性,关键字“Basic”的第一个字母必须大写为“B”,分界字符串必须用双引号(不是单引号)引用;并且在标头行 HTTP/1.0 401 中,在 401 前必须有且仅有一个空格。
在以上例子中,仅仅只打印出了 PHP_AUTH_USER 和 PHP_AUTH_PW 的值,但在实际运用中,可能需要对用户名和密码的合法性进行检查。或许进行数据库教程的查询,或许从 dbm 文件中检索。
注意有些 Internet Explorer 浏览器本身有问题。它对标头的顺序显得似乎有点吹毛求疵。目前看来在发送 HTTP/1.0 401 之前先发送 WWW-Authenticate 标头似乎可以解决此问题。
自 PHP 4.3.0 起,为了防止有人通过编写脚本来从用传统外部机制认证的页面上获取密码,当外部认证对特定页面有效,并且 安全模式 被开启时,PHP_AUTH 变量将不会被设置。但无论如何, REMOTE_USER 可以被用来辨认外部认证的用户,因此可以用 $_SERVER[REMOTE_USER] 变量。
配置说明: PHP 用是否有 AuthType 指令来判断外部认证机制是否有效。
注意,这仍然不能防止有人通过未认证的 URL 来从同一服务器上认证的 URL 上偷取密码。
Netscape Navigator 和 Internet Explorer 浏览器都会在收到 401 的服务端返回信息时清空所有的本地浏览器整个域的 Windows 认证缓存。这能够有效的注销一个用户,并迫使他们重新输入他们的用户名和密码。有些人用这种方法来使登录状态“过期”,或者作为“注销”按钮的响应行为。
例子 34-3. 易做图重新输入用户名和密码的 HTTP 认证的范例
<?php
function authenticate () {
header ( WWW-Authenticate: Basic realm="Test Authentication System" );
header ( HTTP/1.0 401 Unauthorized );
echo "You must enter a valid login ID and password to access this resourcen" ;
exit;
}
if (!isset( $_SERVER [ PHP_AUTH_USER ]) ||
( $_POST [ SeenBefore ] == 1 && $_POST [ OldAuth ] == $_SERVER [ PHP_AUTH_USER ])) {
authenticate ();
}
else {
echo "<p>Welcome: { $_SERVER [ PHP_AUTH_USER ]} <br />" ;
echo "Old: { $_REQUEST [ OldAuth ]} " ;
echo "<form action= { $_SERVER [ PHP_SELF ]} METHOD=post> n " ;
echo "<input type=hidden name=SeenBefore value=1 />n" ;
echo "<input type=hidden name=OldAuth value= { $_SERVER [ PHP_AUTH_USER ]} /> n " ;
echo "<input type=submit value=Re Authenticate />n" ;
echo "</form></p>n" ;
}
该行为对于 HTTP 的 Basic 认证标准来说并不是必须的,因此不能依靠这种方法。对 Lynx 浏览器的测试表明 Lynx 在收到 401 的服务端返回信息时不会清空认证文件,因此只要对认证文件的检查要求没有变化,只要用户点击“后退”按钮,再点击“前进”按钮,其原有资源仍然能够被访问。不过,用户可以通过按“_”键来清空他们的认证信息
在下例中,我们是使用$PHP_AUTH_USER和$PHP_AUTH_PW这两个变量来验证进入者是否合法并允许进入。在本例中被允许登录的用户名称和密码对分别为tnc和nature:
<?
if(!isset($PHP_AUTH_USER))
{
Header("WWW-Authenticate: Basic realm="My Realm"");
Header("HTTP/1.0 401 Unauthorized");
echo "Text to send if user hits Cancel buttonn";
exit;
}
else
{
if ( !($PHP_AUTH_USER=="tnc" && $PHP_AUTH_PW=="nature") )
{
// 如果是错误的用户名称/密码对,强制再验证
Header("WWW-Authenticate: Basic realm="My Realm"");
Header("HTTP/1.0 401 Unauthorized");
echo "ERROR : $PHP_AUTH_USER/$PHP_AUTH_PW is invalid.";
exit;
}
else
{
echo "Welcome tnc!";
}
?>
事实上再实际引用中不大可能如上面使用代码段明显的用户名称/密码对,而是利用数据库或者加密的密码文件存取它们。
6.3 根据指定的验证信息核实用户身份
首先,我们可以使用以下代码确定用户是否已经输入了用户名和密码,并显示出用户输入的信息。
<?php
if (!isset($PHP_AUTH_USER)) {
header(’WWW-Authenticate: Basic realm="My Private Stuff"’);
header(’HTTP/1.0 401 Unauthorized’);
echo ’Authorization Required.’;
exit;
}
else {
echo "<P>You have entered this username: $PHP_AUTH_USER<br>
You have entered this password: $PHP_AUTH_PW<br>
The authorization type is: $PHP_AUTH_TYPE</p>";
}
?>
说明:
isset()函数用于确定某个变量是否已被赋值。根据变量值是否存在,返回true或false。
header()函数用于发送特定的HTTP标头。注意,使用header()函数时,一定要在任何产生实际输出的HTML或PHP代码前面调用该函数。
虽然上述代码相当简单,没有根据任何实际值对用户输入的用户名和密码
补充:综合编程 , 安全编程 ,