Extbase 中的访问检查

Access check in Extbase

我有一项琐碎的任务,但我不知道处理它的预期方式。 我有一个控制器:

public function getObjectAction($object) {}

而且我想确保只有在 $object->getOwner() === $loggedInUser

时才会执行该操作

现在的问题是:这张支票应该是怎样的?

  1. 动作内部的简单 if() 条件,在发生访问冲突时抛出 Exception。我不喜欢这个解决方案,因为它会迫使我在每个需要这样检查的动作中添加这样一个 if() 。当然,我可以创建一些特征,执行此检查并从每个这样的控制器操作调用 ->checkAccess(),但它对我来说仍然看起来很脏。

  2. 控制器参数验证器。似乎是更可靠的解决方案,因为我有单独的 class,它只执行它应该执行的操作(验证访问权限)。但这真的是验证还是误用?

  3. 一些重系统,基于信号,在动作发出之前发送。

  4. 您的变体(也许,已经有一些 ObjectAccessCheck class 左右,我还不知道)。

Source form TYPO3 lists

方案一很简单,你可以把它弄脏一点。

假设你想对控制器中的每个动作执行检查,你可以只使用 initializeAction:

public function initializeAction() {
    if (!$this->myObjectService->isAuthenticatedUserOwnerOfObject($this->arguments['myObject'])) {
        $code = 401;
        $message = 'Authorization Required';
        $this->response->setStatus($code, $message);
        $this->response->shutdown();
    }
}

如果您的控制器中有不需要此检查的操作,您可能希望将其拆分为两个控制器,一个用于受保护的方法,一个用于不受保护的方法。

您还可以对每个动作使用神奇的初始化*动作,例如在你的情况下:

public function initializeGetObjectAction()

最后我决定选择第 3 项。当前的应用程序逻辑是这样的,任何在参数中具有 MyObject 的控制器都应该执行访问检查。

我的ext_localconf.php

$signalSlotDispatcher->connect(
    \TYPO3\CMS\Extbase\Mvc\Controller\ActionController::class,
    'beforeCallActionMethod',
    \MyVendor\MyExt\Slot\MyObjectAccessor::class,
    'actionAuthorized'
);

\MyVendor\MyExt\Slot\MyObjectAccessor

class MyObjectAccessor{

    use LoggedInUserAccessor;

    /**
     * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface
     * @inject
     */
    protected $objectManager;

    /**
     * Checks whether current user is allowed to access MyObject, from provided arguments
     * @param string $controller
     * @param string $action
     * @param array $arguments
     * @throws AccessViolationException
     */
    public function actionAuthorized($controller, $action, array $arguments) {
        foreach($arguments as $argument) {
            // if MyObject is accessed and it was persisted before
            if(($argument instanceof MyObject) && $argument->getUid()) {
                $loggedInUser = $this->getLoggedInUser();
                if($argument->getUser() !== $loggedInUser) {
                    throw new AccessViolationException(
                        'Access violation by "' . $loggedInUser->getUsername() . '" with MyObject "' . $argument->getTitle() . '"',
                        1441808407
                    );
                }
            }
        }
    }
}

该方案的缺点:slot 为任何动作运行,可能会占用一些资源。

好处:控制器不应该知道有关 MyObject 访问规则的详细信息。