2016-01-13 83 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

總是樂於提供幫助。我正在進行的一個項目可能會需要這個(功能蠕變變得非常糟糕),所以它可以幫助我們兩個。我可能只是一直在尋找自己試圖解決問題的方法。 –

相關問題