Zend Framework 检查 docblock 标签的控制器类

发布于 2024-12-03 18:37:53 字数 727 浏览 5 评论 0原文

我想实现一个基于注释的授权 FrontController 插件,就像 ASP.NET Mvc 一样。 我想我可以编写一个前端控制器插件并将授权检查添加到 Zend Framework 提供的 Hooks 之一中。示例:

class My_Controller_Plugin_Authorize extends Zend_Controller_Plugin_Abstract {
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request){
        ...
        if($user_is_not_loggedin){
             goSomeWhereElse();
        }
    }
}

class MyFancyController extends Zend_Controller_Action{

   /**
    * @Authorize
    */
    public function secretAction(){
        ...
    }
}

现在我需要检查实际请求的控制器中的文档块,以查明用户要执行的操作是否需要授权。 事实证明事情并不那么简单:请求对象是传递到 Hook 的唯一资源。

我以为我可以通过执行controllerName +“Controller”来构建控制器的类名,但该类不会自动加载,因此找不到它并且代码崩溃了。

有什么想法吗?

I wanted to implement an Authorization FrontController Plugin based on Annotations just like ASP.NET Mvc.
I thought I could write a front controller plugin and add the Authorization check into one of the Hooks provided by Zend Framework. Example:

class My_Controller_Plugin_Authorize extends Zend_Controller_Plugin_Abstract {
    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request){
        ...
        if($user_is_not_loggedin){
             goSomeWhereElse();
        }
    }
}

class MyFancyController extends Zend_Controller_Action{

   /**
    * @Authorize
    */
    public function secretAction(){
        ...
    }
}

Now I need to inspect docblocks in the actual requested controller to find out if the action the user is heading to requires to be authorized or not.
And it turned out to be not so simple: the Request Object is the only resource that gets passed into the Hooks.

I thought I could build the controller's class name by doing controllerName + "Controller" but the class doesn't get autoloaded and so it's not found and the code crushes.

Any Ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一抹淡然 2024-12-10 18:37:53

正如您在对问题的评论中指出的那样,调度程序可以访问实际的控制器实例 - 而不仅仅是控制器名称

另一个可以访问控制器实例的地方是 action helper ,它可以访问控制器实例。那么,也许有一个带有 preDispatch() 钩子的动作助手来执行基于反射的文档块内省?可能会受到一些性能影响,因为反射被认为很慢。

但是,一般来说,这听起来像是您想要访问控制,通常使用 Zend_Acl 来处理,然后编写一个利用该 ACL 对象的控制器插件。除非您确实需要对 ACL 的文档块注释进行基于反射的检查,否则我会采用 ACL/插件方法。

As you note in your comment to your question, the dispatcher has access to the actual controller instance - as opposed to just the controller name.

Another place that has access to the controller instance is an action helper, which has access to the controller instance. So perhaps an action helper with a preDispatch() hook that performs the reflection-based docblock introspection? Probably some performance hit, as reflection is considered slow.

But, in general, this sounds like you want access-control, which is usually handled using Zend_Acl and then writing a controller plugin that utilizes that ACL object. Unless you really need to do reflection-based inspection of docblock annotations for your ACL, I'd go with the the ACL/plugin approach.

从来不烧饼 2024-12-10 18:37:53

这是我的解决方案。 @Authorize 注释既可以在类的顶部工作,也可以在单个方法的顶部工作。
显然可以扩展到用ACL来检查。

<?php
class Ant_Controller_Plugin_Authorize extends Zend_Controller_Plugin_Abstract {

    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request){
        $frontController = Zend_Controller_Front::getInstance();
        $dispatcher = $frontController->getDispatcher();
        $controllerClass = $dispatcher->getControllerClass($request);
        $dispatcher->loadClass($controllerClass);
        $reflectionClass = new Zend_Reflection_Class($controllerClass);
        $reflectionMethod = $reflectionClass->getMethod($dispatcher->getActionMethod($request));
        try {
            $authClass = $reflectionClass->getDocblock()->hasTag("Authorize");
        } catch (Exception $e) {
            $authClass = false;
        }
        try{
            $authMethod = $reflectionMethod->getDocblock()->hasTag("Authorize");
        }catch (Exception $e){
            $authMethod = false;
        }

        if($authClass || $authMethod){
            if(!Zend_Auth::getInstance()->hasIdentity()){
                $request->setActionName("login")->setControllerName("Accounts");
                $request->setDispatched(false);
            }
        }
    }
}

然后在application.ini中

resources.frontController.plugins.Authorize = "Ant_Controller_Plugin_Authorize"

This si my solution. The @Authorize annotation works either on the top of the class or on the top of the single methods.
Obviously can be extended to check with ACL.

<?php
class Ant_Controller_Plugin_Authorize extends Zend_Controller_Plugin_Abstract {

    public function dispatchLoopStartup(Zend_Controller_Request_Abstract $request){
        $frontController = Zend_Controller_Front::getInstance();
        $dispatcher = $frontController->getDispatcher();
        $controllerClass = $dispatcher->getControllerClass($request);
        $dispatcher->loadClass($controllerClass);
        $reflectionClass = new Zend_Reflection_Class($controllerClass);
        $reflectionMethod = $reflectionClass->getMethod($dispatcher->getActionMethod($request));
        try {
            $authClass = $reflectionClass->getDocblock()->hasTag("Authorize");
        } catch (Exception $e) {
            $authClass = false;
        }
        try{
            $authMethod = $reflectionMethod->getDocblock()->hasTag("Authorize");
        }catch (Exception $e){
            $authMethod = false;
        }

        if($authClass || $authMethod){
            if(!Zend_Auth::getInstance()->hasIdentity()){
                $request->setActionName("login")->setControllerName("Accounts");
                $request->setDispatched(false);
            }
        }
    }
}

and then in the application.ini

resources.frontController.plugins.Authorize = "Ant_Controller_Plugin_Authorize"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文