如何访问请求对象在Sym2 FOSUserBundle自定义UserChecker


how to access request object in Sym2 FOSUserBundle custom UserChecker

我使用Synfony2和FOSUserBundle,我有一个自定义userChecker,我想验证用户的主机(我们有几个主机指向相同的IP)。我的问题是,在我的自定义userChecker我不能访问请求,因此不是请求的主机。

这是我的用户检查代码

/*
 * This file is part of the Symfony package.
 *
 * (c) Fabien Potencier <fabien@symfony.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
//Override by Mattias
namespace BizTV'UserBundle'Controller;
//namespace Symfony'Component'Security'Core'User;
use Symfony'Component'Security'Core'Exception'CredentialsExpiredException;
use Symfony'Component'Security'Core'Exception'LockedException;
use Symfony'Component'Security'Core'Exception'DisabledException;
use Symfony'Component'Security'Core'Exception'AccountExpiredException;
use Symfony'Component'Security'Core'User'UserInterface;
use Symfony'Component'Security'Core'User'UserChecker as OriginalUserChecker;
use Symfony'Component'HttpFoundation'Request as Request; //ADDED BY MW
/**
 * UserChecker checks the user account flags.
 *
 * @author Fabien Potencier <fabien@symfony.com>
 */
class UserCheckerNew extends OriginalUserChecker
{
    /**
     * {@inheritdoc}
     */
    public function checkPreAuth(UserInterface $user)
    {
/*
        //Test for companylock...
        if ( !$user->getCompany()->getActive() ) {
            throw new LockedException('The company of this user is locked.', $user);
        }
        if ( $user->getLocked() ) {
            throw new LockedException('The admin of this company has locked this user.', $user);
        }
*/
        if (!$user instanceof AdvancedUserInterface) {
            return;
        }
        if (!$user->isCredentialsNonExpired()) {
            throw new CredentialsExpiredException('User credentials have expired.', $user);
        }

    }
    /**
     * {@inheritdoc}
     */
    public function checkPostAuth(UserInterface $user)
    {
        //Test for companylock...
        if ( !$user->getCompany()->getActive() ) {
            throw new LockedException('The company of this user is locked.');
        }    
        if ( $user->getLocked() ) {
            throw new LockedException('The admin of this company has locked this user.');
        }
/*
Validate HOST here
*/
        if (!$user instanceof AdvancedUserInterface) {
            return;
        }
        if (!$user->isAccountNonLocked()) {
            throw new LockedException('User account is locked.', $user);
        }
        if (!$user->isEnabled()) {
            throw new DisabledException('User account is disabled.', $user);
        }
        if (!$user->isAccountNonExpired()) {
            throw new AccountExpiredException('User account has expired.', $user);
        }
    }
}

在checkPostAuth函数中,我尝试了不同的东西,比如传递请求

public function checkPostAuth(UserInterface $user, Request $request)

错误提示我的重写必须符合原始/接口。

尝试在控制器中获取请求

$this->container->get('request_stack')->getCurrentRequest();

或者像这样

$currentHost = $request->getHost();

或者像这样

$cont = $this->getContainer();

或者像这样

$request = $this->getRequest();

或者像这样

$request = $container->get('request');

然而没有运气=)我不是Symfony2专家,正如你所看到的,我在这里只是随便说说=)


增加配置参数。根据gp- sflower的回答,我的配置。Yml现在看起来像这样:

services:
    security.user_checker:
        class: BizTV'UserBundle'Controller'UserCheckerNew
        arguments: [ "@request" ]
        scope: request
        public: true

在scope:request被添加到配置之前传递的错误是:

Scope Widening Injection detected: The definition "security.user_checker" references the service "request" which belongs to a narrower scope. Generally, it is safer to either move "security.user_checker" to scope "request" or alternatively rely on the provider pattern by injecting the container itself, and requesting the service "request" each time it is needed. In rare, special cases however that might not be necessary, then you can set the reference to strict=false to get rid of this error.'

当添加scope: request时,返回一个非常类似的错误

Scope Widening Injection detected: The definition "security.authentication.provider.dao.main" references the service "security.user_checker" which belongs to a narrower scope. Generally, it is safer to either move "security.authentication.provider.dao.main" to scope "request" or alternatively rely on the provider pattern by injecting the container itself, and requesting the service "security.user_checker" each time it is needed. In rare, special cases however that might not be necessary, then you can set the reference to strict=false to get rid of this error

添加public: true似乎没有什么不同。还有,我不知道这些公开的东西到底是什么意思,也许是安全问题?公众这个词总是让人害怕的=)

而不是扩展"OriginalUserChecker"类,你可以覆盖security.user_checker服务,以便能够注入request_stack作为参数,然后在你的UserChecker类中检索它,就像这个简单的例子:

service . xml

// Symfony >=2.6
<service id="security.user_checker"
         class="Your'Bundle'Path'ToYour'UserCheckerClass">
    <argument type="service" id="request_stack"/>
</service>
// Symfony <2.6
<service id="security.user_checker"
         class="Your'Bundle'Path'ToYour'UserCheckerClass">
    <argument type="service" id="request" public="true" scope="request"/>
</service>

UserCheckerClass

use Symfony'Component'Security'Core'User'UserCheckerInterface;
// Symfony >=2.6
use Symfony'Component'HttpFoundation'RequestStack;
// Symfony <2.6
use Symfony'Component'HttpFoundation'Request;
class UserChecker implements UserCheckerInterface
{
    private $request;
    public function __construct(
        // Symfony >=2.6
        RequestStack $request
        // Symfony <2.6
        Request $request
    ) {
        $this->request = $request;
    }
    public function checkPreAuth(UserInterface $user)
    {
        // your checks here
    }
    public function checkPostAuth(UserInterface $user)
    {
        // your checks here
    }
}

我从来没有让请求注入工作。然而,我确实获得了整个服务容器的注入来工作。

这就是我最终的做法,在gp_sflover的指导下(如果你用这个代码发布答案,我会检查你的答案是否正确,我不想窃取信誉,只是把真相拿出来;])

services:
    security.user_checker:
        #class: BizTV'UserBundle'Controller'UserChecker
        class: BizTV'UserBundle'Controller'UserCheckerNew
        arguments: ["@service_container"]

namespace BizTV'UserBundle'Controller;
use Symfony'Component'Security'Core'User'UserCheckerInterface;
use Symfony'Component'DependencyInjection'ContainerInterface;
use Symfony'Component'Security'Core'User'UserInterface;
use Symfony'Component'Security'Core'Exception'CredentialsExpiredException;
use Symfony'Component'Security'Core'Exception'LockedException;
use Symfony'Component'Security'Core'Exception'DisabledException;
use Symfony'Component'Security'Core'Exception'AccountExpiredException;

class UserCheckerNew implements UserCheckerInterface
{
    protected $container;
    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }
    public function checkPreAuth(UserInterface $user)
    {
        if (!$user instanceof AdvancedUserInterface) {
            return;
        }
        if (!$user->isCredentialsNonExpired()) {
            throw new CredentialsExpiredException('User credentials have expired.', $user);
        }
    }
    /**
     * {@inheritdoc}
     */
    public function checkPostAuth(UserInterface $user)
    {
//Validate HOST here, make it look as though account doesn't exist if on wrong host
        $host = $this->container->get('request')->getHost();
        if ($host != "localhost") { //bypass all checks when on localhost
            $brandedHost = $user->getCompany()->getBrandedHost();
            if ( $brandedHost == "" ) { //if unset assume main
                $brandedHost = "login.mydomain.se";
            }
            if ( $host != $brandedHost ) {
                throw new LockedException('Invalid username or password.'); //dot added for debug
            }
        }
// end of host validation
        //Test for companylock...
        if ( !$user->getCompany()->getActive() ) {
            throw new LockedException('The company of this user is locked.');
        }    
        if ( $user->getLocked() ) {
            throw new LockedException('The admin of this company has locked this user.');
        }
        if (!$user instanceof AdvancedUserInterface) {
            return;
        }
        if (!$user->isAccountNonLocked()) {
            throw new LockedException('User account is locked.', $user);
        }
        if (!$user->isEnabled()) {
            throw new DisabledException('User account is disabled.', $user);
        }
        if (!$user->isAccountNonExpired()) {
            throw new AccountExpiredException('User account has expired.', $user);
        }
    }
}