动网论坛,站长建站首选,国内使用量最多的论坛软件 动网论坛官方技术讨论区 站长工具 申请属于您自己的免费论坛
首页 | 新闻资讯 | 网站运营 | 网络编程 | 数据库 | 服务器 | 网页设计 | 图像媒体 | 网络应用 | 搜索优化 | 资源下载 | 动网主机 | DVBOX
    本站内  互联网 ASP论坛  ASP.Net论坛  PHP论坛
  
   PHP → 阅读文章

 PHP 用户认证

作者来源: 
阅读 1183 人次 , 2006-3-29 4:06:00 


在专门 web 网站上,常常会需要用户的帐号及密码,也就是身份确认的步骤。早期的 ncsa httpd 服务器 并没有提供这项用户确认的功能,webmaster 只能用手工打造一个身份确认的 cgi 程序。

自 cern httpd 之后的 web 服务器大部份都提供了用户身份确认的功能。仅管每套 web 服务器的配置都不太相同,但在配置上都大同小异。

以下就是 apache 服务器上的用户身份确认的配置。

<directory /home/mymember> authtype basic authname mymember authuserfile /usr/local/mymember.txt options includes execcgi <limit get post> require valid-user </limit> </directory>

在这个例子中,当用户在看 mymember 目录下所有的文件,包括图片文件及其它各式文件时,都需要用户的帐号密码确认。而用户的帐号及密码文件都存在于 /usr/local/mymember.txt 之中。

这个帐号密码文件 /usr/local/mymember.txt 的样子可能如下例。其中冒号前的字符串是用户帐号,冒号之后的字符串是经过不可还原加密的密码,编码一般都是使用传统的 des 编码,密码的头两个字是类似种子的字符 (salt),本例中都是 3p。每行代表一位用户。当然 webmaster 要自行控制重覆帐号的情形。比较特殊是在 win32 系统上架 apache 的情形,冒号后的密码不可加密,因为 win32 没有提供这方面的编码 api,因此用户密码以明码的方式存在。

john1234:3pwudbljmiwro queenwan:3pfnvlnpn9w0m noname00:3pesxajx5pk7e wilson49:3pjowb0enag22 rootboot:3pit0sni6.84e sun_moon:3pvymmenoc.x. nobody38:3pbskpkwv94hw

在 apache 1.3.6 版上,可以用 ~apache/bin/htpasswd 来产生单笔的帐号及密码,但对于需要大笔资料的商业网站,可能就需要自行写程序来处理了。unix 上需要调用 crypt() 来处理编码。

img/5.2.1.gif

在一切都配置好了之后,连接时就会在浏览器出现查核密码的窗口,如上图就是 seednet 的 myseed 网站的用户查核机制。在输入了帐号及密码后,浏览器会将它用 base64 编码后,传到服务器端。当然 base64 只是编码不是加密,因此在网络上这种传输的安全性仍然不高,还是有可能被中间的刽客截下,再将 base64 还原,这也是整个用户认证中最美中不足的地方,或许日后支持摘要认证 (digest) 及使用 md5 编码后,可以解决这种问题。之后每一页仍然需要帐号及密码,只不过浏览器会帮你主动送出,不用再输入帐号密码了。这方面浏览器会保留到被关闭为止,下次重执行浏览器仍需输入第一次。

在用户数量少时,使用上述的方法轻松又省事。但是在用户有数万人,甚至数十万人时,会发生整个服务器的效率都被搜寻帐号密码下拖垮,可能读取一页需要数十秒到数分钟。这种情形再使用服务器提供的密码查核机制就不太明智了。在 netscape enterprise server 上可能就可以使用 nsapi 来开发自己的查核方式,在 iis 上也可以用 isapi 过滤器开发。写 c/c++ 程序调用 nsapi/isapi 总是很累,在 php 上有了另外的选择,这也是本节的主题。


php 的 http 相关函数库提供了 header() 的函数。许多 web 服务器与客户端的互动,都可以使用这个函数来变戏法。例如在某个 php 页面最开始处,也就是第一行或第二行,加入以下的程序,可以将用户重定向到作者的网页。

<?php
header ( "location: http://wilson.gs" );
exit;
?>

当然,在上述程序之后的 html 文字或者是 php 程序都永远不会出现在用户端了。

同样的道理,我们就用 header() 来变用户认证的把戏。可以在 php 的最开头送出字符串到用户端,就会在用户端出现下图的窗口。

<?php
header ( "www-authenticate: basic realm=\"member\"" );
header ( "http/1.0 401 unauthorized" );
?>

img/5.2.2.gif

在程序中字符串 realm=\"member\" 中的 member 字样出现在图中,当然若使用中文字取代,浏览器端也会出现中文字,如上面的 myseed 图。若 web 网站用户还有其它语文,如英文或日文,送出中文的 realm 字符串似乎就比较不合适。无论如何,这都要视网站的性质及用户定位而决定。

当然这还是很粗糙,因为除了送出窗口后,就没有下文了,帐号输入正确也好,输入错误也罢,都不会有任何的结果。我们需要再更进阶的程序来处理。


在后端的使用认证上,考虑使用数据库作为储存帐号及密码的后端,在这种架构可以容纳许多的用户,管它一万个用户还是十万个用户。若您的站已有数十万个用户帐号,那么恭喜您,您的站算是世界级的大站了。 mysql 是个不错的选择,许多网站,甚至是商业化的网站都用它来做后端的数据库。当然您要架真正的商业网站,钱不是问题的话,那可以使用口碑最广的 oracle 数据库系列。

要在 php 中使用任何数据库,都要先将数据库的服务器端及客户端配置好,之后才编译 php 及 apache 系统。

准备好 mysql 及 php 之后,先在 mysql 中加入新的数据库,本例是加入 mymember,用别的名字当然也可以。mysql 要加入数据库 (database) 很容易,只要在 mysql 存放 database 的地方 mkdir 就可以了。例如在 unix shell 下打

hahaha:/usr/local/mysql/data# mkdir mymember

在建立了数据库之后,尚需要建立资料表格 (table) 方能使用。配置的表格如下,可以将它储在 /tmp/memberauth.sql 中

create table memberauth ( serial mediumint(9) not null auto_increment, username char(8) not null, password char(8) not null, enable char(1) default '0' not null, primary key (serial) ); 文件 memberauth.sql

先看看 memberauth.sql 的这些字段。serial 是个自动增加的整数字段,每输入一笔资料,就会自动加一,这当然不能是空的字段,于是就用 not null 了。第两个字段是 username,代表用户的帐号,为了统一以及适应各系统起见,配置成八个字,当然这个字段也不能是空的。password 是第三个字段,为用户的密码。第四个字段 enable 做为帐号是否有效的标志,设计上 0 表示无用,1 表可用,日后还可加入其它值做不同的用途。

设计好了资料表之后,就要将资料表加入数据库了。由于常要使用 mysql 数据库,可以到 http://www.phpwizard.net/phpmyadmin 下载 phpmyadmin,使用浏览器操作及管理 mysql,轻松又方便。若使用这套 phpmyadmin 可以在它的用户界面上输入 memberauth.sql 加入 mysql 中。或者也可以在 unix shell 下输入下式,也是有同样的效果。

mysql mymember < /tmp/memberauth.sql

在准备好了之后,就可以输入用户帐号及密码在 memberauth 资料表中了。当然还是使用 phpmyadmin 方便,用 mysql 程序就要一笔笔的 insert 了。

img/5.2.3.gif

接着进入了设计函数的阶段了。

<?php
//---------------------------
// 用户认证函数 auth.inc
// author: wilson peng
// copyright (c) 1999
//---------------------------
$error401 = "/home/phpdocs/error/401.php" ;
if ( $php_auth_pw == "" ) {
header ( "www-authenticate: basic realm=\"超金卡会员\"" );
header ( "http/1.0 401 unauthorized" );
include( $error401 );
exit;
} else {

$db_id = mysql_pconnect ( "localhost" , "myid" , "mypw" );
$result = mysql_db_query ( "mymember" , "select password, enable from memberauth where username='$php_auth_user'" );

$row = mysql_fetch_array ( $result );
$memberpasswd = $row [ 0 ];
$memberenable = $row [ 1 ];
if ( $memberenable == 0 ) {
echo "您的帐号被停用了" ;
exit;
}

if ( $php_auth_pw != $memberpasswd ) {
header ( "www-authenticate: basic realm=\"超金卡会员\"" );
header ( "http/1.0 401 unauthorized" );
include( $error401 );
exit;
}
}
?>
copyright (c) 1999, wilson peng

要使用这个 auth.inc,要在每个 php 的第一行加入
<? require( "auth.inc" ); ?> 。在加入本程序的 php 文件都会检查帐号密码,图片等就不会检查,比起使用 web 服务器功能的某目录下全都检查,php 显得有弹性多了。

$error401 = "/home/phpdocs/error/401.php" ;

这行表示在用户按下取消,或检查失败时,要显示给用户看的文件。

if ( $php_auth_pw == "" ) {
header ( "www-authenticate: basic realm=\"超金卡会员\"" );
header ( "http/1.0 401 unauthorized" );
include( $error401 );
exit;
} else {

到 else 之前,若没有传入密码,则送出输入密码的窗口。其中的 $php_auth_user、$php_auth_pw 是 php 中特殊的变量,分别代表用户确认的帐号及密码。上面的程序也是利用这两个变量来处理用户认证。

img/5.2.4.gif

$db_id = mysql_pconnect ( "localhost" , "myid" , "mypw" );
$result = mysql_db_query ( "mymember" , "select password, enable from memberauth where username='$php_auth_user'" );

$row = mysql_fetch_array ( $result );
$memberpasswd = $row [ 0 ];
$memberenable = $row [ 1 ];

若用户有输入帐号及密码,则向数据库查询。同时查核该用户是否仍可使用。

if ( $memberenable == 0 ) {
echo "您的帐号被停用了" ;
exit;
}

上四行程序为帐号被停用的情形。

if ( $php_auth_pw != $memberpasswd ) {
header ( "www-authenticate: basic realm=\"超金卡会员\"" );
header ( "http/1.0 401 unauthorized" );
include( $error401 );
exit;
}

密码错误则再次向用户要求输入帐号及密码。

在实际使用时,可以视需要加入的网页再加入 auth.inc 这个文件,就不用连看张图形也要查一次密码,轿募服务器和用户二端的资源。当然,和 mysql 的连系上,可以使用 mysql_pconnect() 一直和 mysql 服务器连接。或是使用 mysql_connect() 每次重新连接,用这个函数要记得早点使用 mysql_close() 将数据库关闭。下面的程序 auth1.inc 是另一版本的认证程序,就是打开连接后马上关闭,释放资源的例子。

<?php
//---------------------------
// 用户认证函数-1 auth1.inc
// author: wilson peng
// copyright (c) 1999
//---------------------------
$error401 = "/home/phpdocs/error/401.php" ;
if ( $php_auth_pw == "" ) {
header ( "www-authenticate: basic realm=\"超金卡会员\"" );
header ( "http/1.0 401 unauthorized" );
include( $error401 );
exit;
} else {

$db_id = mysql_connect ( "localhost" , "myid" , "mypw" );
$result = mysql_db_query ( "mymember" , "select password, enable from memberauth where username='$php_auth_user'" );

$row = mysql_fetch_array ( $result );
$memberpasswd = $row [ 0 ];
$memberenable = $row [ 1 ];
mysql_close ( $db_id );
if ( $memberenable == 0 ) {
echo "您的帐号被停用了" ;
exit;
}

if ( $php_auth_pw != $memberpasswd ) {
header ( "www-authenticate: basic realm=\"超金卡会员\"" );
header ( "http/1.0 401 unauthorized" );
include( $error401 );
exit;
}
}
?>
copyright (c) 1999, wilson peng

在实际应用时,可以在数据库中加入更多功能,如用户分组 (cug) 的功能;或是加入时间字段,可做到期检查。其中的变化,端赖设计者的巧思了。

 
 收藏本文  打印本文  论坛讨论  关闭窗口
· 上一篇:PHP 聊天室
· 下一篇:php 访客计数器
· MySql正则表达式的描述
· SNMP 网管函数库
· 一个全面获取图象信息的函数getImageInfo()
· 解码mime
· 浅谈PHP语法


关于本站 | 联系我们 | 业务合作 | 客户案例 | 诚聘英才 | 广告合作 | 收藏本站
海口动网先锋网络科技有限公司版权所有
Copyright © 2000 - 2006 Cndw.Com
中华人民共和国电信与信息服务业务经营许可证编号 琼 ICP 020077