Routes 是否可以使用Symfony`?“切换”用户`;注销“;在模仿之间?

Routes 是否可以使用Symfony`?“切换”用户`;注销“;在模仿之间?,routes,twig,impersonation,symfony,Routes,Twig,Impersonation,Symfony,我正在使用的网站在导航栏中为超级用户提供了一个搜索框,这样他们就可以从一组普通用户中进行选择,然后将所选用户名传递给Symfony的?\u switch\u user=功能进行模拟 我正在使用jQuery返回当前页面的路由,并为所需用户添加适当的?\u switch\u user=username,如下所示: 小枝: {% if is_granted('ROLE_PREVIOUS_ADMIN') %} <form class="navbar-form navbar-left"

我正在使用的网站在导航栏中为超级用户提供了一个搜索框,这样他们就可以从一组普通用户中进行选择,然后将所选用户名传递给Symfony的
?\u switch\u user=
功能进行模拟

我正在使用jQuery返回当前页面的路由,并为所需用户添加适当的
?\u switch\u user=username
,如下所示:

小枝:

{% if is_granted('ROLE_PREVIOUS_ADMIN') %}
      <form class="navbar-form navbar-left" role="search">
            <div class="form-group">
                 <input type="text" id="search-names" class="form-control" placeholder="User name">
            </div>
      </form>
      <li><a href="{{ path( app.request.get('_route'), {'_switch_user':'_exit'})  }}">~Return To Admin~<span class="sr-only">Return To Admin</span></a></li>
{% endif %}
$(function() {
  $("#search-names").autocomplete({
        source: "{{ path('usersearch') }}",
        minLength: 2,
        select: function (event, matched) {
             console.log(matched)
             window.location = window.location + '?_switch_user=' + matched.item.value
        }
  });
})
在上面,我必须包含
~Return to Admin~
链接,以便超级用户可以“注销”每个模拟-否则Symfony返回一个错误,表示另一个交换机用户已经登录

如果他们可以从一个普通用户切换到另一个用户,而不必每次都请求
?\u switch\u user=\u exit
(尽管我仍然会保留按钮,因为当他们只执行管理员任务时需要它)


有没有一个简单的方法来实现这一点?我发现一篇文章建议通过创建一个新的listener“”来解决这个问题(他们文章中的“第二个功能”),但是我无法实现这一点,我想知道这是否是由于Symfony 3的结构差异造成的?

我终于有空继续修改您链接到Symfony 3的代码。下面的代码应使“返回管理员”功能如链接中所述,并使其能够在已切换时直接切换到其他用户

<?php
namespace AppBundle\Listener;


use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Role\SwitchUserRole;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Event\SwitchUserEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\Security\Http\Firewall\SwitchUserListener;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;

class MySwitchUserListener extends SwitchUserListener
{
    private $useOverrideUri = true;

    public function handle(GetResponseEvent $event)
    {
        $request = $event->getRequest();

        if( !$request->get( $this->usernameParameter ) )
            return;

        if('_exit' === $request->get( $this->usernameParameter ) )
            $this->tokenStorage->setToken( $this->attemptExitUser( $request ) );
        else{
            try{
                $this->tokenStorage->setToken( $this->attemptSwitchUser( $request ) );
            }catch( AuthenticationException $e ){
                throw new \LogicException(sprintf('Switch User failed: "%s"', $e->getMessage()));
            }
        }

        $request->query->remove( $this->usernameParameter );

    $overrideUri = $session->get( 'onSwitchURI', NULL );
    if( $request->get( 'returnTo' ) ){
        $session->set( 'onSwitchURI', $request->get( 'returnTo' ) );
        $request->query->remove( 'returnTo' );
    }
    else
        $session->remove( 'onSwitchURI' );

        $request->server->set( 'QUERY_STRING', http_build_query( $request->query->all() ) );
        $response = new RedirectResponse( $request->getUri(), 302 );
        $event->setResponse( $response );
    }

    private function attemptSwitchUser(Request $request)
    {
        $token = $this->tokenStorage->getToken();

        $originalToken = $this->getOriginalToken($token);

        if (false !== $originalToken) {
            if ($token->getUsername() === $request->get($this->usernameParameter)) {
                return $token;
            }
            $token = $originalToken;
            $this->useOverrideUri = false;
        }
        if (false === $this->accessDecisionManager->decide($token, array($this->role)))
            throw new AccessDeniedException();

        $username = $request->get($this->usernameParameter);

        if(null !== $this->logger)
            $this->logger->info('Attempting to switch to user.', array('username' => $username));

        $user = $this->provider->loadUserByUsername($username);
        $this->userChecker->checkPostAuth($user);
        $roles = $user->getRoles();
        $roles[] = new SwitchUserRole( 'ROLE_PREVIOUS_ADMIN', $token );
        $token = new UsernamePasswordToken( $user, $user->getPassword(), $this->providerKey, $roles );
        if (null !== $this->dispatcher) {
            $switchEvent = new SwitchUserEvent($request, $token->getUser());
            $this->dispatcher->dispatch(SecurityEvents::SWITCH_USER, $switchEvent);
        }
        return $token;
    }

}

我在您提供的链接和Symfony 3代码中看到的最大区别是,该链接使用了已被弃用的SecurityContext。看看新的SwitchUserListener的链接,你应该能够很容易地将链接的技术应用到新的签名中。非常感谢你花时间来解决这个问题-我还没有能够实现它,但一旦我回到那个项目,我会做的!总是乐于助人。我参与的一个项目很可能最终需要这个功能(功能爬行已经变得非常糟糕了,哈哈),所以它对我们双方都有帮助。我可能只是在这里看着我自己试图解决这些问题。