使用 Zend_Auth 和 Zend_Db 实现用户认证(ZF Study)
<文章大部分内容取自《PHP Web 2.0 》这本书>,最近在学习这本书 ^ ^
来记录一下如何使用 Zend Framework(ZF)来实现用户的认证操作:
首先先来看看 ZF 手册对 Zend_Auth 组件的简介:
Zend_Auth 为认证(authentication)和一些通用用例情景的具体认证适配器提供了一个API。
Zend_Auth 只涉及 认证而不是授权。认证被宽松地定义为基于一些证书(credential)来确定一个实体(例如,身份)是否确实是它所声称的。授权是一个过程,它决定是否允许一个实体对其他实体进行访问、执行操作,它超出了Zend_Auth的范围。更多关于Zend Framework 授权和访问控制的信息,参见 Zend_Acl.
Note: Zend_Auth 类通过它的 getInstance()方法实现 Singleton 模式 - 只有一个实例可用。这意味着使用 new 操作符和 clone 关键字将不能在Zend_Auth 类中工作,而要使用 Zend_Auth::getInstance() 来代替。
1,数据库表信息
在我们的 MySQL 里新建一个 phpweb20 数据库及 users 表,作为测试,建表的 SQL 语句如下所示:
CREATE TABLE `users` ( `user_id` bigint(20) unsigned NOT NULL auto_increment, `username` varchar(255) NOT NULL, `password` varchar(32) NOT NULL, `user_type` varchar(20) NOT NULL, `ts_created` datetime NOT NULL, `ts_last_login` datetime default NULL, PRIMARY KEY (`user_id`), UNIQUE KEY `user_id` (`user_id`), UNIQUE KEY `username` (`username`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=gbk
主键为 user_id 字段。
2,Zend_Auth 如何工作
首先我们要理解 Zend_Auth 所使用的术语,标识一个用户的唯一信息称为其“身份”,用户成功地认证以后,将其身份存储在一个 PHP 会话之中,从而在以后的页面中能够标识这些用户。(关于这里的 PHP 会话,Zend_Auth 为此提供了一个 Zend_Auth_Storage_Session 类,而这个类又进一步使用了 Zend_Session 组件,这实际上是 PHP 的 $_SESSION 变量的一个包装器,而且提供了更强大的功能)
要认证一个用户,用户必须提供一个凭证,在我们的例子当中,使用 users 表中的 password 作为用户的凭证,我们将使用一个适配器根据数据库来检查给定的用户的身份和凭证。这个适配器是 Zend_Auth_Adapter_DbTable 适配器,这个适配器设计为使用 Zend_Db 组件,如果要是想编写自己的适配器,只需实现一个方法:authenticate() 方法,该方法要返回一个 Zend_Auth_Result 对象。这个对象包含着认证是否成功的有关信息,还包含一些诊断信息。
3,实例化 Zend_Auth
Zend_Auth 是一个单例类,使用静态的 getInstance() 方法来获取这个实例,然后必须使用 setStorage() 方法设置存储类(要注意,我们使用的是 PHP 的会话):
以下代码用于建立 Zend_Auth 实例:
$auth = Zend_Auth::getInstance(); $auth -> setStorage(new Zend_Auth_Storage_Session());
4,如何完成认证
来说一些具体的关于 Zend_Auth_Adapter_DbTable 的东西:
我们将使用 Zend_Auth_Adapter_DbTable 认证适配器,使用这个适配器之前,必须已经有一个合法的 Zend_Db 对象。它的实例化需要 5 个参数:
> 合法的 Zend_Db 对象($db); > 所用数据库表的名(这里使用的是 users); > 保存用户身份的列(username 字段); > 保存用户凭证的列(password 字段); > 最后一点,对凭证的处理。这实际上是包装凭证的一个函数,假如存储用户信息的时候,password 字段存放的是用户密码的 MD5 散列值,那么我们就要把 md5(?) 作为最后一个参数传入。此问号只是 Zend_Db 在哪里带入口令值。
一旦实例化了 Zend_Auth_Adapter_DbTable ,就可以设置身份(username)和凭证(password)了,为此要使用 setIdentity() 和 setCredential() 方法。接下来,在 $auth 对象(Zend_Auth 的实例)上调用 authenticate() 方法,而传入 anthenticate() 方法的唯一参数是适配器($adapter),通过它来返回一个 Zend_Auth_Result 的一个实例。还可以通过调用 Zend_Auth_Result 对象的 isValid() 方法来查看用户是否通过了认证,还可以调用其他的方法来查看错误信息。
实现代码如下:
<?php /** * 使用 Zend_Auth 和 Zend_Db 实现用户认证 */ //启用 ZF 的自动调用机制(必备的一步) require_once('Zend/Loader/Autoloader.php'); $autoloader = Zend_Loader_Autoloader::getInstance(); $autoloader->setFallbackAutoloader(true); //数据库配置数组 $params = array('host' => 'localhost', 'username' => 'root', 'password' => 'password', 'dbname' => 'phpweb20' ); $db = Zend_Db::factory('pdo_mysql', $params); //初始化 Zend_Auth 组件 $auth = Zend_Auth::getInstance(); $auth -> setStorage(new Zend_Auth_Storage_Session()); //初始化认证适配器 $adapter = new Zend_Auth_Adapter_DbTable($db, 'users', 'username', 'password', 'md5(?)'); //设置身份 $adapter -> setIdentity('fakeUsername'); //设置密码 $adapter -> setCredential('fakePassword'); //验证 $result = $auth -> authenticate($adapter);//返回 Zend_Auth_Result 实例 if($result -> isValid()) { //登录成功 echo "Succeed!"; } else { //登录失败 switch($result -> getCode()) { case Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND: echo 'Identity not found!'; break; case Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS: echo 'Multiple users found with this identity!'; break; case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID: echo 'Invalid password!'; break; default: var_dump($result -> getMessages()); } } ?>
其实还可以使用 $auth 对象来检查一个用户是否通过认证。hasIdentity() 方法指示一个用户是否通过认证,为了确定用户的具体身份,可以使用 getIdentity() 方法。类似地,可以使用 clearIdentity() 方法来注销用户,如果使用 PHP 会话作为存储方法,实际上,这会从会话中删除指定用户的身份。