【问题标题】:Zend_Auth best practicesZend_Auth 最佳实践
【发布时间】:2011-04-01 12:46:11
【问题描述】:

我的目标是要求登录某些页面。我正在使用 Zend Framework MVC,并且正在尝试查找有关最佳实践的示例。

关于我正在寻找的内容的一些说明:

  • 我希望非登录用户获得一个登录框,然后在通过身份验证后返回登录版本的页面
  • 我想使用依赖注入,避免单例
  • 代码占用空间小 - 与 Zend mvc 结构相关
  • 登录框是否应该是一个单独的控制器并进行标头重定向?认证成功后如何返回登陆页面?一个简单地调用登录控制器操作以在登录页面中显示登录框的想法,或者这是搜索引擎索引的一个缺点?
  • 能够使用外部库来处理 cookie

或者完全不同的东西。我对 Zend 框架还很陌生,我想以“正确的方式”来做。

【问题讨论】:

    标签: php zend-framework authentication zend-framework-mvc


    【解决方案1】:
    • 我想让非登录用户得到一个登录框,然后返回登录 在页面的版本中,一次 认证

    使用 FrontController plugin 并将它们重定向或转发到您的 loginAction。

    • 我想使用依赖注入,避免单例

    Zend 框架目前不提供任何 DI 系统,但是 Zend_Application_Resource_* 实际上取代了它。这里需要什么样的依赖?

    • 代码占用空间小 - 与 Zend mvc 结构相关

    这取决于你。

    • 登录框是否应该是一个单独的控制器并进行标头重定向?如何 验证后返回登录页面 成功?一个简单地调用的想法 登录控制器操作以显示 登陆页面中的登录框,或者是 这是关于搜索的一个缺点 引擎索引?

    我主要使用特殊的AuthController 和LoginAction 和LogoutAction。要将用户重定向到试图查看的页面,我总是在我的表单中添加一个returnUrl 元素,并注入请求的 URL 的值以便能够重定向用户,如果没有,我将他重定向到索引/仪表板,取决于。

    • 能够使用外部库来处理 cookie

    Zend_Auth 允许你设置你的own storage mechanism,所以只需实现接口。

    $auth = Zend_Auth::getInstance();
    $auth->setStorage(new My_Auth_Storage());
    

    但是 从不将身份验证结果存储在 cookie 中,修改它并访问您的网站非常容易。

    你也可以看看我的previous answer。

    【讨论】:

    • 关于所需的依赖 - 特别是会话存储处理程序。关于 cookie 身份验证 - 我已经实现了 jaspan.com/improved_persistent_login_cookie_best_practice 的设计原则,我希望利用它。
    • 如果你真的要使用DI,你可以使用Symfony DI,它可以很好地集成在ZFblog.starreveld.com/2009/11/…中,但是如果你只打算使用它来进行Auth可能会产生开销。您仍然可以编写 AuthService 并使用应用程序资源 $this->getInvokeArg('boostrap')->getResource('AuthService'); 来检索它。或使用 Zend_Registry。
    • 如何在没有引荐来源的 https 页面上填充“returnUrl”?
    • 您可以在您的 Auth Front Controller 插件中附加一个 GET 参数并重定向到您的 Auth 控制器,或者您可以在 $_SESSION 中进行设置,但多次打开的选项卡可能会导致结果不一致
    【解决方案2】:

    您可以使用Zend_Auth 和Zend_Acl 的组合。为了扩展其他答案,我举了一个简短的例子来说明如何使用 zend 框架管理身份验证:

    首先您需要设置一个插件来predispatch所有请求并检查是否允许客户端访问某些数据。这个插件可能看起来像这样:

    class Plugin_AccessCheck extends Zend_Controller_Plugin_Abstract {
    
        private $_acl = null;
    
        public function __construct(Zend_Acl $acl) {
            $this->_acl = $acl;
        }
    
        public function preDispatch(Zend_Controller_Request_Abstract $request) {
            //get request information
            $module = $request->getModuleName ();
            $resource = $request->getControllerName ();
            $action = $request->getActionName ();
    
            try {
                if(!$this->_acl->isAllowed(Zend_Registry::get('role'), 
                                    $module . ':' . $resource, $action)){
                    $request->setControllerName ('authentication')
                            ->setActionName ('login');
                }
            }catch(Zend_Acl_Exception $e) {
                $request->setControllerName('index')->setActionName ('uups');
            }
        }
    }
    

    因此,每种用户类型都具有您在 acl 库中定义的某些权限。在每次请求时,您都会检查是否允许用户访问资源。如果不是,则重定向到登录页面,否则 preDispatch 会将用户传递给资源。

    在Zend_Acl 中,您定义允许或拒绝访问的角色、资源和权限,例如:

    class Model_LibraryAcl extends Zend_Acl {
        public function __construct() {
    
            $this->addRole(new Zend_Acl_Role('guests'));
            $this->addRole(new Zend_Acl_Role('users'), 'guests');
            $this->addRole(new Zend_Acl_Role('admins'), 'users');                
    
            $this->add(new Zend_Acl_Resource('default'))
                 ->add(new Zend_Acl_Resource('default:authentication'), 'default')
                 ->add(new Zend_Acl_Resource('default:index'), 'default')
                 ->add(new Zend_Acl_Resource('default:error'), 'default');
    
            $this->allow('guests', 'default:authentication', array('login'));
            $this->allow('guests', 'default:error', 'error');
    
            $this->allow('users', 'default:authentication', 'logout');          
        }
    }
    

    然后你必须在你的引导文件中设置 acl 和 auth:

        private $_acl = null;
    
        protected function _initAutoload() {
    
           //...your code           
           if (Zend_Auth::getInstance()->hasIdentity()){
            Zend_Registry::set ('role',
                         Zend_Auth::getInstance()->getStorage()
                                                  ->read()
                                                  ->role);
            }else{
                Zend_Registry::set('role', 'guests');
            }
    
            $this->_acl = new Model_LibraryAcl ();
            $fc = Zend_Controller_Front::getInstance ();
            $fc->registerPlugin ( new Plugin_AccessCheck ( $this->_acl ) );
    
            return $modelLoader;
        }
    

    最后,在您的身份验证控制器中,您必须使用自定义 auth 适配器 并设置登录和注销操作:

    public function logoutAction() {
        Zend_Auth::getInstance ()->clearIdentity ();
        $this->_redirect ( 'index/index' );
    }
    
    private function getAuthAdapter() {
        $authAdapter = new Zend_Auth_Adapter_DbTable ( 
                            Zend_Db_Table::getDefaultAdapter ());
        $authAdapter->setTableName('users')
                    ->setIdentityColumn('email')
                    ->setCredentialColumn ('password')
                    ->setCredentialTreatment ('SHA1(CONCAT(?,salt))');
    
        return $authAdapter;
    }
    

    在您的登录操作中,您需要将登录数据传递给执行身份验证的身份验证适配器。

    $authAdapter = $this->getAuthAdapter ();
    $authAdapter->setIdentity ( $username )->setCredential ( $password );
    $auth = Zend_Auth::getInstance ();
    $result = $auth->authenticate ( $authAdapter );
    
    if ($result->isValid ()) {
        $identity = $authAdapter->getResultRowObject ();
        if ($identity->approved == 'true') {
            $authStorage = $auth->getStorage ();
            $authStorage->write ( $identity );
            $this->_redirect ( 'index/index' );
        } else {
           $this->_redirect ( 'authentication/login' );
      }
    

    仅此而已。我向你推荐这个HOW TO on youtube on zend auth 和 zend acl。

    【讨论】:

    • 这是我在 SO 上见过的最完整的答案! +1 为此!
    【解决方案3】:

    不确定这是否是最佳做法,但如果我要实现你所追求的,那么我会执行以下操作:

    1. 创建一个带有唯一可识别提交按钮的LoginForm(稍后解释)
    2. 使用方法getLoginForm、login、logout 和以下一种或全部方法创建AuthService:getIdentity、hasIdentity 和类似方法。
    3. 创建一个具有此服务实例的 viewhelper,并根据 hasIdentity 的结果在需要此功能的视图中呈现 LoginForm 或呈现登录用户的身份。李>
    4. 创建一个前端控制器插件,该插件也有一个服务实例,并实现preDispatch 插件钩子。给它一些要探测的操作的配置。如果 AuthService->hasIdentity() 返回 true,则什么也不做。如果请求是发布请求,则查找唯一可识别的提交按钮名称,即:$request->getPost( 'loginSubmitButton', null );,如果不可用,默认为 null。如果不是null,请在服务上执行login( $request->getPost() )。如果成功,则重定向到相同的操作,如果不成功,则再次在 viewhelper 中呈现表单(自动显示错误)。

    viewhelper 和前端控制器插件都可以获取服务,其中一些服务定位器通过在引导程序中将服务注册到 ServiceAbstract 来执行类似 ServiceAbstract::getService( 'Auth' ) 的操作。

    【讨论】:

      猜你喜欢
      • 2011-01-04
      • 1970-01-01
      • 2010-09-05
      • 2014-12-21
      • 2010-12-23
      • 2010-10-14
      • 2023-03-19
      • 2011-11-08
      • 2010-11-03
      相关资源
      最近更新 更多