实现简单的访问控制并不困难。程序清单17-1所示的代码可以将输出3个可能结果之一。
如果没有使用参数载入文件,该代码将显示一个要求输入用户名和密码的HTML表单。该表单类型如图17-1所示。
图 17-1 HTML表单要求访问者提供访问站点所需的用户名和密码如果用户提交了这些参数,但是参数不正确,该代码将显示一个错误信息。错误信息如图17-2所示。
图 17-2 当用户输入了不正确的信息时,将给出一个出错信息。在一个真正的网站上,可能要给出一个更友好的信息如果用户提交了这些参数并且参数正确,它将显示该页的秘密内容。测试内容如图17-3所示。
图 17-3 当用户提交正确的详细信息时,脚本将显示内容创建如图17-1、图17-2和图17-3所示功能的代码如程序清单17-1所示。
程序清单17-1 secret.php——提供简单的身份验证机制的PHP和HTML
<?php
//create short names for variables
$name=$_POST[/'name/'];
$password=$_POST[/'password/'];
if((!isset($name))||(!isset($password))){
//Visitor needs to enter a name and password
?>
<h1>Please Log In</h1>
<p>This page is secret.</p>
<form method=/"post/"action=/"secret.php/">
<p>Username:<input type=/"text/"name=/"name/"></p>
<p>Password:<input type=/"password/"name=/"password/"></p>
<p><input type=/"submit/"name=/"submit/"></p>
</form>
<?php
}else if(($name==/"user/")&&($password==/"pass/")){
//visitor/'s name and password combination are correct
echo/"<h1>Here it is!</h1>
<p>I bet you are glad you can see this secret page.</p>/";
}else{
//visitor/'s name and password combination are not correct
echo/"<h1>Go Away!</h1>
<p>You are not authorized to use this resource.</p>/";
}
?>
程序清单17-1所示的代码提供了一个简单的身份验证机制,它允许通过身份验证的用户浏览某个网页,但是它存在一些明显的问题。
该脚本:
■在脚本中只对一个用户名和密码进行了硬编码。
■将密码以普通文本形式保存。
■只保护一个页面。
■以普通文本形式传输密码。
通过不同程度的努力和实践,我们可以逐一解决这些问题。
17.2.1 保存密码
与将用户名和密码保存在脚本中相比,还有许多更好的用来保存用户名和密码的地方。在以上脚本中,要修改数据将会是非常困难的。编写一段脚本来修改脚本本身是可能的,但这却是一个非常糟糕的主意。这意味着服务器中有一脚本,它在服务器中执行,但是可以被其他脚本写入或者修改。将数据保存在服务器的另一个文件可以使我们能够轻松地编写一个用来添加和删除用户以及修改密码的程序。
在不至于严重影响脚本的执行速度前提下,一个脚本或者其他数据文件内部能够保存的用户数量是有限的。正如前面所介绍的,如果考虑在一个文件中保存并查找大量的项目,应该考虑使用一个数据库来代替。如果要保存和搜索的内容多于100个项目,应该使用一个数据库而不是一个普通文件来实现,这是一条重要的规则。
使用数据库来保存用户名和密码将不会使脚本复杂很多,但是这将允许我们快速地验证不同用户的身份。它也允许我们轻松地编写一段脚本来添加新用户、删除用户并且允许用户修改自己的密码。
通过数据库验证访问者身份的脚本如程序清单17-2所示。
程序清单17-2 secretdb.php——使用MySQL来改进原有的简单身份验证机制
<?php
$name=$_POST[/'name/'];
$password=$_POST[/'password/'];
if((!isset($name))||(!isset($password))){
//Visitor needs to enter a name and password
?>
<h1>Please Log In</h1>
<p>This page is secret.</p>
<form method=/"post/"action=/"secretdb.php/">
<p>Username:<input type=/"text/"name=/"name/"></p>
<p>Password:<input type=/"password/"name=/"password/"></p>
<p><input type=/"submit/"name=/"submit/"></p>
</form>
<?php
}else{
//connect to mysql
$mysql=mysqli_connect(/"localhost/",/"webauth/",/"webauth/");
if(!$mysql){
echo/"Cannot connect to database./";
exit;
}
//select the appropriate database
$selected=mysqli_select_db($mysql,/"auth/");
if(!$selected){
echo/"Cannot select database./";
exit;
}
//query the database to see if there is a record which matches
$query=/"select count(*)from authorized_users where
name=/'/".$name./"/'and
password=/'/".$password./"/'/";
$result=mysqli_query($mysql,$query);
if(!$result){
echo/"Cannot run query./";
exit;
}
$row=mysqli_fetch_row($result);
$count=$row[0];
if($count>0){
//visitor/'s name and password combination are correct
echo/"<h1>Here it is!</h1>
<p>I bet you are glad you can see this secret page.</p>/";
}else{
//visitor/'s name and password combination are not correct
echo/"<h1>Go Away!</h1>
<p>You are not authorized to use this resource.</p>/";
}
}
?>
数据库也可以通过以MySQL root用户的身份连接MySQL并运行程序清单17-3的脚本来创建。
程序清单17-3 createauthdb.sql——这些MySQL查询语句将创建auth数据库、auth表和两个示例用户
create database auth;
use auth;
create table authorized_users(name varchar(20),
password varchar(40),
primary key(name)
);
insert into authorized_users values(/'username/',
/'password/');
insert into authorized_users values(/'testuser/',
sha1(/'password/'));
grant select on auth.*
to/'webauth/'
identified by/'webauth/';
flush privileges;