Zend Framework 教程 – Zend_Auth

作者 FarLee 2012年4月12日 22:46:00   ‖浏览(13,047)

Zend Framework 教程 >> Zend_Auth

Zend Framework的Zend_Auth组件负责基于证书验证一个用户的过程的认证,这个证书通常是用户名和密码。这节教程主要介绍了如何使用登录表单将Zend_Auth 整合到应用中。在Zend Framework 1.10版本中已经测试,之前的版本可能不能正常工作。

Zend_Auth 将核心组件和一套adapters 区分了开来。adapters 包含了针对指定系统验证用户的实际代码,如HTTP,数据库,LDAP等。一旦成功登录,Zend_Auth 核心对象将可以访问identity,identity 是包含了登录时收集到的信息(如用户名/密码等)的一组值,identity 里具体是什么值由使用的adapter 决定。比如HTTP adapter 将会返回用户名,以及数据库表 adapter 已经访问到的数据表整行的那些数据。

用户数据库

首先我们在MySQL数据库中创建一个名为users 的表,如:

CREATE TABLE IF NOT EXISTS users (
  id int(11) NOT NULL AUTO_INCREMENT,
  username varchar(50) NOT NULL,
  password varchar(50) NOT NULL,
  salt varchar(50) NOT NULL,
  role varchar(50) NOT NULL,
  date_created datetime NOT NULL,
  PRIMARY KEY (id)
)

然后添加一个用户数据,让它可以登录:

INSERT INTO users (username, password, salt, role, date_created)
VALUES ('admin', SHA1('passwordce8d96d579d389e783f95b3772785783ea1a9854'),
	'ce8d96d579d389e783f95b3772785783ea1a9854', 'administrator', NOW());

这个用户用户名为username,密码为password。为了增加安全性,我们使用了一个“salt”值,让用户登录时和密码配合使用。目的是使SHA1值在www.sha1-lookup.com 是不可逆的。salt的实际值是什么并不重要,只要随机的就可以。在MySQL中运行上面的SQL语句。

Auth 控制器和登录表单

我们在一个独立的控制器 – AuthController 里实现登录和登出功能。转到zf项目的根目录,使用ZF 命令行工具创建控制器文件和view 代码:

zf create controller Auth

这将在application/controllers/AuthController.php 文件中创建一个包含 indexAction 的AuthController 类,以及在登录过程中要用到的相应的view 代码文件。同样我们还需要一个登录表单:

zf create form Login

这将在application/forms/Login.php 文件中创建Application_Form_Login 类,我们给它添加3个元素:username 文本区域、password 密码区域和submit 提交按钮:

class Application_Form_Login extends Zend_Form
{
    public function init()
    {
        $this->setName("login");
        $this->setMethod('post');

        $this->addElement('text', 'username', array(
            'filters'    => array('StringTrim', 'StringToLower'),
            'validators' => array(
                array('StringLength', false, array(0, 50)),
            ),
            'required'   => true,
            'label'      => 'Username:',
        ));

        $this->addElement('password', 'password', array(
            'filters'    => array('StringTrim'),
            'validators' => array(
                array('StringLength', false, array(0, 50)),
            ),
            'required'   => true,
            'label'      => 'Password:',
        ));

        $this->addElement('submit', 'login', array(
            'required' => false,
            'ignore'   => true,
            'label'    => 'Login',
        ));        
    }
}

现在我们需要在controller 控制器中加载form 表单,并在view 代码中呈现,和前面章节的Zend Framework教程中控制器类似:

application/controllers/AuthController.php

    // ...
    public function indexAction()
    {
        $form = new Application_Form_Login();
        $request = $this->getRequest();
        if ($request->isPost()) {
            if ($form->isValid($request->getPost())) {
                // do something here to log in
            }
        }
        $this->view->form = $form;
    }
    // ...

相应的view 文件代码为:
application/views/scripts/auth/index.phtml

<?php $this->headTitle('Login'); ?>
<h1>Login</h1>
<?php echo $this->form->setAction($this->url()); ?>

访问 http://localhost/zftest/public/auth 显示类似如下的表单。

zend_auth 登录表单

Zend_Auth 认证

为了实现认证过程,我们要将上面的// do something here to log in用实际的认证代码替换。为简单起见,我们将必须的代码放入AuthController 控制器,虽然在大型应用中,你可能需要考虑使用一个服务层对象(service layer object)。

我们将创建一个名为_process()的方法来完成这任务,将 application/controllers/AuthController.php 的indexAction() 改成以下代码:

    // ...
    public function indexAction()
    {
        $form = new Application_Form_Login();
        $request = $this->getRequest();
        if ($request->isPost()) {
            if ($form->isValid($request->getPost())) {
                if ($this->_process($form->getValues())) {
                    // We're authenticated! Redirect to the home page
                    $this->_helper->redirector('index', 'index');
                }
            }
        }
        $this->view->form = $form;
    }
    // ...

你可以看到我们添加了一个对 _process() 私有方法的调用,如果返回True,使用redirector 这个 action helper跳转到首页。_process() 方法如下:

application/controllers/AuthController.php

    // ...
    protected function _process($values)
    {
        // Get our authentication adapter and check credentials
        $adapter = $this->_getAuthAdapter();
        $adapter->setIdentity($values['username']); 
        $adapter->setCredential($values['password']);

        $auth = Zend_Auth::getInstance();
        $result = $auth->authenticate($adapter);
        if ($result->isValid()) {
            $user = $adapter->getResultRowObject();
            $auth->getStorage()->write($user);
            return true;
        }
        return false;
    }
    // ...

上面的代码使用另外一个私有方法 _getAuthAdapter() 来创建担当实际认证工作的 Zend_Auth_Adapter_DbTable 对象。一旦创建了这对象,我们使用setIdentity 方法告诉它用户输入的用户名,setCredential 方法告诉它密码。

在告诉了adapter 所需要的信息之后,我们使用 $auth = Zend_Auth::getInstance(); 抓取 Zend_Auth 对象,Zend_Auth的 authenticate 方法用于测试提供的用户名和密码是否正确。

如果正确,我们就用getResultRowObject()从用户表中获取这个用户的数据(stdClass),然后将它保存到auth adapter 供后续的请求使用。

_getAuthAdapter() 的代码如下:

application/controllers/AuthController.php

    // ...
    protected function _getAuthAdapter() {

        $dbAdapter = Zend_Db_Table::getDefaultAdapter();
        $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);

        $authAdapter->setTableName('users')
            ->setIdentityColumn('username')
            ->setCredentialColumn('password')
            ->setCredentialTreatment('SHA1(CONCAT(?,salt))');

        return $authAdapter;
    }
    // ...

我们实例化了一个Zend_Auth_Adapter_DbTable,从 Zend_Db_Table 传递给它一个默认的数据库 adapter,而 Zend_Application 的application.ini设置已经配置了Zend_Db_Table了(resources.db.adapter = “Pdo_Mysql”)。接下来我们就可以告诉它使用users 数据库表,identity 列和credential 列分别是username 和password。

我们使用 setCredentialTreatment 告诉 adapter 密码是以SHA1 保存的,认证过程中 salt 区域的值必须加到提供的密码后面。如果没有使用salt或SHA1,移除这一行数据库将使用明文密码。

现在用户可以通过 http://localhost/zftest/public/auth 填写用户名密码登录了(admin-password)。

谁在登录?

既然用户已经登录,Web应用一般都会要求显示用户名和提供一个注销的链接。我们可以使用view helper来实现:

application/views/helpers/LoggedInAs.php

<?php 
class Zend_View_Helper_LoggedInAs extends Zend_View_Helper_Abstract 
{
    public function loggedInAs ()
    {
        $auth = Zend_Auth::getInstance();
        if ($auth->hasIdentity()) {
            $username = $auth->getIdentity()->username;
            $logoutUrl = $this->view->url(array('controller'=>'auth',
                'action'=>'logout'), null, true);
            return 'Welcome ' . $username .  '. <a href="'.$logoutUrl.'">Logout</a>';
        } 

        $request = Zend_Controller_Front::getInstance()->getRequest();
        $controller = $request->getControllerName();
        $action = $request->getActionName();
        if($controller == 'auth' && $action == 'index') {
            return '';
        }
        $loginUrl = $this->view->url(array('controller'=>'auth', 'action'=>'index'));
        return '<a href="'.$loginUrl.'">Login</a>';
    }
}

上面的代码很简单,最重要的是我们获取了Zend_Auth对象,然后检测用户是否使用hasIdentity() 登录了。如果用户有登录,我们就使用getIdentity() 获取前面加载的数据 – 在这个例子中是username。

然后在application/views/scripts/auth/index.phtml 或layout.html 文件中,我们可以添加以下代码:

<div id="header"> <div id="logged-in-as">
<?php echo $this->loggedInAs(); ?> </div>
</div>

用户登出

对于用户登出注销,我们在 AuthController 类中创建了另外一个action logoutAction:

zf create action logout Auth

application/controllers/AuthController.php

    // ...
    public function logoutAction()
    {
        Zend_Auth::getInstance()->clearIdentity();
        $this->_helper->redirector('index'); // back to login page
    }
    // ...

Zend_Auth 的clearIdentity 方法执行了注销,然后跳转的指定的页面。为了控制哪些用户允许登录,即用户访问控制列表的管理,推荐使用Zend_Acl 组件


“Zend Framework 教程 – Zend_Auth”文章评论(2)

  1. 小疯风流

    Zend_Auth中的用户名应为admin,密码为:password.请不要搞错了。有点疑问,一直不理解SHA1的用处。。。

  2. For the love of God, keep writing these arsitlec.

来说兩句