schedb/two_factor_bundle:如何使用exclude_pattern进行身份验证路由


scheb/two_factor_bundle: how to use exclude_pattern for authenticated route?

我在Symfony3项目中使用Scheb的双因子捆绑包,我想以不同的方式处理exclude_pattern参数,但我不知道如何处理。

通常,exclude_pattern用于将未经身份验证的路由从双因素身份验证中排除,如调试页面或静态内容:

# config/config.yml
scheb_two_factor:
    ...
    exclude_pattern: ^/(_(profiler|wdt)|css|images|js)/

它的行为是这样实现的:

/* vendor/scheb/two-factor-bundle/Security/TwoFactor/EventListener/RequestListener.php */
public function onCoreRequest(GetResponseEvent $event)
{
    $request = $event->getRequest();
    // Exclude path
    if ($this->excludePattern !== null && preg_match('#'.$this->excludePattern.'#', $request->getPathInfo())) {
        return;
    }
    ...
}

我还想为经过身份验证的路由处理exclude_pattern,这样在调用它们时可以跳过双因素身份验证。对于已验证,我的意思是在security.yml下的access_control部分内,如下所示:

# app/config/security.yml
security:
    ...
    access_control:
        - { path: ^/test, role: ROLE_USER }

现在,如果我在exclude_pattern下添加一个经过身份验证的路由,我得到的只是一个AccessDeniedException,这可能是因为捆绑包要求将access_decision_manager参数设置为strategy: unanimous

目的很长,而且英语不是我的母语,但如果你真的需要知道,我可以试着解释。

我用symfony3和symfony2标记了这个问题,因为我使用的是Symfony 3.0,但我很确定它在Symfony 2.8中是相同的。

我通过覆盖捆绑包中的Voter类找到了一个解决方案:

// AppBundle/Security/TwoFactor/Voter.php
namespace AppBundle'Security'TwoFactor;
use Scheb'TwoFactorBundle'Security'TwoFactor'Session'SessionFlagManager;
use Symfony'Component'Security'Core'Authentication'Token'TokenInterface;
class Voter extends 'Scheb'TwoFactorBundle'Security'TwoFactor'Voter
{

    /**
     * @var string
     */
    protected $excludePattern;
    /**
     * Voter constructor.
     * @param SessionFlagManager $sessionFlagManager
     * @param array $providers
     * @param $excludePattern
     */
    public function __construct(SessionFlagManager $sessionFlagManager, array $providers, $excludePattern)
    {
        parent::__construct($sessionFlagManager, $providers);
        $this->excludePattern = $excludePattern;
    }
    /**
     * @param TokenInterface $token
     * @param mixed          $object
     * @param array          $attributes
     *
     * @return mixed result
     */
    public function vote(TokenInterface $token, $object, array $attributes)
    {
        if ($this->excludePattern !== null && preg_match('#'.$this->excludePattern.'#', $object->getPathInfo()))
        {
            return true;
        }
        parent::vote($token, $object, $attributes);
    }
}

# app/config/services.yml
services:
    ...
    scheb_two_factor.security_voter:
    class: 'AppBundle'Security'TwoFactor'Voter'
    arguments:
        - '@scheb_two_factor.session_flag_manager'
        - ~
        - '%scheb_two_factor.exclude_pattern%'

这样,每当触发GetResponseEvent时,就会调用右侧的Voter,如果exclude_pattern与路径匹配,它将对true进行投票。