2016-01-13 22 views
2

我正在使用的网站在超级用户的导航栏中包含一个搜索框,以便他们可以从常规用户数组中选择,这些用户将所选用户名传递给Symfony的?_switch_user=功能以模拟。是否可以使用Symfony`_ _switch_user`而不必在模拟之间进行“注销”?

我使用jQuery返回当前页面的路径并追加相应的?_switch_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 %} 

的jQuery:

$(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会返回一个错误,指出另一个切换用户已登录。

如果可以的话,它会更加“超级用户友好”从一个普通用户切换到另一个,而不必每次请求?_switch_user=_exit(虽然我仍然会保持按钮,在需要时,他们只执行管理任务)

是否有实现这个简单的方法是什么?我找到了一篇文章,建议通过创建一个新的监听器“Making impersonating a user more friendly”(文章中的'第二个功能'),但是我无法得到这个工作,我想知道是否是由于结构上的差异Symfony3?

+0

我在您提供的链接和Symfony 3代码中看到的巨大差异是链接使用已弃用的SecurityContext。查看新的SwitchUserListener的[源代码](http://api.symfony.com/3.0/Symfony/Component/Security/Http/Firewall/SwitchUserListener.html),您应该很容易调整链接的技巧到新的签名。 –

回答

0

我终于得到了空闲时间继续前进,并调整您链接到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; 
    } 

} 
+0

非常感谢您抽出宝贵时间来解决这个问题 - 我还没有能够实现它,但是一旦我回到那个项目,我会做的! – Bendy

+0

总是乐于提供帮助。我正在进行的一个项目可能会需要这个(功能蠕变变得非常糟糕),所以它可以帮助我们两个。我可能只是一直在寻找自己试图解决问题的方法。 –

相关问题