使用Zend_Auth保护所有控制器

时间:2011-02-09 10:59:45

标签: php security zend-framework

我如何全局保护我的所有控制器(我的登录控制器除外)以确保我的应用程序在所有点都是安全的(没有隐藏的后门到ajax调用等)。我以为我可能会把它放在我的bootstrap文件中,但这感觉不对?我试图避免向每个控制器添加任何代码。

建议?

4 个答案:

答案 0 :(得分:11)

编辑:这是@singles响应的补充。

你必须明白有两件事。 验证验证。 Auth告诉您谁是用户,并且您可以例如将没有Auth的用户重定向到登录控制器,并在登录后设置auth身份。然后,Acl系统根据Auth数据做出是/否决定(可以是用户ID,也可以是角色,存储在Auth存储中。

好的解决方案是拥有2个控制器插件(在bootstrap上按照正确的顺序注册,然后是Auth,然后是Acl)。如果您不使用Controller插件,则必须在每个控制器中调用Acl检查。如果你总是需要它,那就使用插件。

如果您没有从Zend_Auth返回身份,请在 Auth插件中实施preDispatch()以设置匿名身份。 这是一个真实的代码片段:

public function preDispatch(Zend_Controller_Request_Abstract $request)
{
    $module = $request->getModuleName();
    $controller = $request->getControllerName();
    $action = $request->getActionName();
    $auth = Zend_Auth::getInstance();
    if (!$auth->hasIdentity()) {
        // set a default anonymous identity
        $auth->getStorage()->write(array('name' => 'anonymous','role' => 1,));
    }
(...)

对于 Acl控制器插件,任务也在preDispatch()中。您可以为每个请求的URL启动acl检查(因此对于每个用户请求,甚至是ajax)。这是一个部分片段,所以这只是一个如何处理事情的例子:

public function preDispatch(Zend_Controller_Request_Abstract $request) {
    $controller = $request->controller;
    $module = $request->module;
    $action = $request->action;
    // here you should code something nice retrieving you Zend_Acl object
    // with some caching options maybe, building roles, ressources, etc
    $this->_acl = $this->getAcl(); 
    if (!$this->_acl->isCurrentUserAllowed($module,'see')) {
        $auth = Zend_Auth::getInstance();
    $identity  = $auth->hasIdentity('identity')? $auth->getIdentity() : null;
    if(isset($identity)) {
            if($identity['name'] == 'anonymous') {
                // WARNING: avoid infinite redirect loops on login page
                if (!($request->getControllerName() == 'login' 
                    && $request->getActionName()=='login' 
                    && $request->getModuleName() == 'default')) {
                        $request->setControllerName('login')
               ->setActionName('login')
               ->setModuleName('default');
            return;
(...)

在这个系统中,最后一个重要的部分是LoginController,如果成功登录,你应该启动身份记录:

(...)
$auth = Zend_Auth::getInstance();
Zend_Session::regenerateId();
$storage = $auth->getStorage();
$rowobject = $authAdapter->getResultRowObject(null,'passwd');
$storage->write((array)$rowobject);
(...)

答案 1 :(得分:4)

你应该为此编写ACL插件并在前端控制器中注册它。如果您实现插件等功能,您可以灵活地在下一个应用程序中使用它 - 无需从自定义控制器扩展每个控制器。

资源:
1. Front Controller Plugins in Zend Framework - 插件如何在ZF中工作
2. Zend_Acl / Zend_Auth example scenario - ACL插件的许多可能实现之一 3. Google - 还有很多其他资源

答案 2 :(得分:0)

嗯,你需要有一个系统的入口点:)

这可以通过扩展Zend_Controller_Action来实现,比如说:

abstract class MyController extends Zend_Controller_Action {
  public function preDispatch(){
    // do the logic
  }
} 

现在每个控制器只需要扩展MyController,你就是安全的。

答案 3 :(得分:0)

我在一个实现中的方式是在我的应用程序路径中创建一个名为Auth.php的文件。然后我打开了我想要保护的每个控制器并添加了行

include_once APPLICATION_PATH . '/Auth.php';

在调用parent :: init()之前的init()方法。

至于Auth.php文件本身,它基本上使用Zend_Auth进行身份验证。成功后,我会保存用户的身份,以便以后在应用程序中使用

$this->view->assign('myIdentity', Zend_Auth::getInstance()->getIdentity());

如果失败,我会重定向到登录页面并传递一些参数,以便登录页面知道我登录后将发送给我的位置。

这不是一个优雅的解决方案,但它可靠且相对快速且易于实施。