这是两个恐怕会用的最多的组件了!
(Zend Framework也许不是最好的框架,但是它一定是代码最易读的框架了!如果要我使用一个自己都看不太懂的框架做开发,那是不可能的,我希望是自己掌握自己的命运)
先看Zend_Auth(使用时和手册的说法还是稍有不同的)
数据库表:
CREATE TABLE `user` (
`uid` SMALLINT( 5 ) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR( 20 ) CHARACTER SET gbk COLLATE gbk_chinese_ci NOT NULL ,
`password` CHAR( 32 ) NOT NULL ,
`role` ENUM( 'user', 'staff', 'admin' ) NOT NULL ,
`truename` VARCHAR( 20 ) CHARACTER SET gbk COLLATE gbk_chinese_ci NOT NULL ,
INDEX ( `role` , `truename` ) ,
UNIQUE (
`username`
)
) ENGINE = MYISAM CHARACTER SET gbk COLLATE gbk_chinese_ci COMMENT = '用户表';
数据库链接文件:
./Lib/Adapter.php
<?php
$adapter = Zend_Db::factory('PDO_MYSQL', array( 'host' => 'localhost',
'username' => 'root',
'password' => 'root',
'dbname' => 'text'));
$adapter->query('set names gbk;');
Zend_Registry::set('Db', $adapter);
使用Zend_Auth进行身份认证:
<?php
require './Zend/Loader.php';
function __autoload($class)
{
Zend_Loader::loadClass($class);
}
//以上为包含文件
$auth = Zend_Auth::getInstance();//->setStorage(new Zend_Auth_Storage_Session('Zend_Auth'));
//身份的持久是自动发生的,因此此举等于$auth = Zend_Auth::getInstance()->setStorage(new Zend_Auth_Storage_Session('Zend_Auth'));
if($auth->hasIdentity())
{
echo '已经登录过了!<br/>';
$session = $auth->getStorage()->read();
echo '显示用户组: ' . $auth->getStorage()->read()->role . '<br/>';
return;
}
//上文是如果已经登录过,若没有登录则完成登录(下面操作)
require './Lib/Adapter.php';
$auth_adapter = new Zend_Auth_Adapter_DbTable(Zend_Registry::get('Db'), 'user', 'username', 'password', 'md5(?)');
$result = $auth->authenticate($auth_adapter->setIdentity('zhangsilly')->setCredential('123456789'));
$auth->getStorage()->write($auth_adapter->getResultRowObject(null, 'password'));
echo '登录完毕<br/>';
echo '显示用户组: ' . $auth->getStorage()->read()->role . '<br/>';
注意:$auth_adapter = new Zend_Auth_Adapter_DbTable(Zend_Registry::get('Db'), 'user', 'username', 'password', 'md5(?)'); 这一句,如果采用和手册一样的写法$credentialTreatment 给 md5 认证是无法成功的!
以上代码运行结果:
第一次运行会显示:
登录完毕
显示用户组: admin
而后的刷新则不会访问数据库(身份的持久是自动运行的),即使关闭MySQL也仍旧可以完成认证!
显示结果:
已经登录过了!
显示用户组: admin
上面的实现中,我存储了一个Enum类型的变量在数据库中,标示用户角色,正好可以和 Zend_Acl 配套使用!
Zend_Acl的测试:
<?php
require './Zend/Loader.php';
function __autoload($class)
{
Zend_Loader::loadClass($class);
}
//添加访问控制链 Acl
$acl = new Zend_Acl;
$acl->add(new Zend_Acl_Resource('Default'));
$acl->add(new Zend_Acl_Resource('News'));
//上面对应我的两个module,一个Default,一个News
$acl->addRole(new Zend_Acl_Role('guest'));
$acl->addRole(new Zend_Acl_Role('user'), 'guest');
$acl->addRole(new Zend_Acl_Role('staff'), 'user');
$acl->addRole(new Zend_Acl_Role('admin'));
$acl->allow('guest', array('Default', 'News'), 'view');
$acl->allow('user', array('Default', 'News'), array('reply', 'download'));
$acl->allow('staff', array('Default', 'News'), array('delete', 'update'));
$acl->allow('admin');
echo $acl->isAllowed('admin', 'News' , 'view')?'Yes':'No';
执行的结果是愉快的,Zend Acl正确的给出了我想要的结果
(背景资料:我的程序有两个模块Module,Default和 News模块,我将其作为两个资源看待!)
体会:Zend_Acl默认采用黑名单策略,只要没有说明允许就默认deny,但是使用allow方法进行授权时则有采用的白名单策略,如果为给出具体的资源或者权限(给值为Null),则认为允许所有的
在Zend_Auth中覆盖它原有的写行为,将认证后的结果集写如Session中,其中包含一个role字段,正好可以给Zend_Acl进行授权。。。
两个租件一起使用还是蛮方便的!
不过有点疑问是:如同Discuz之类的程序,各个角色的权限是可以由管理员改动的,貌似这样做的话就被限制死了,如果将权限存如数据库的话,那么将导致在任何一次请求中都会造成访问数据库初始化访问控制链表,应该会影响效率!采用php 数组存放这些内容倒是可以考虑的,不过没有测试