2012-04-10 11 views
8

Vorrei controllare da dentro un controller se si tratta di una pagina protetta o meno. Come fare questo?Symfony2: come verificare se un'azione è protetta?

mio caso d'uso è la seguente:

  • utente può registrarsi ed effettuare il login
  • Se egli accede e cerca di accedere a una pagina protetta, sarà reindirizzato a una pagina "versione beta" fino la fine di giugno.
  • Se cerca di accedere a una pagina normale (non assicurata), egli sarà in grado di accedervi senza alcun reindirizzamento.

Grazie per il vostro aiuto!

Aurel

+0

Non sono sicuro di cosa stai cercando di ottenere. Quando l'utente digita l'azione URL (o viene reindirizzata a) ** quell'azione è protetta o non è sicura **. I controllori non possono avere più azioni (protette e non protette) con lo stesso nome, a causa del nome del metodo, ovviamente. Puoi comunque chiedere a SecureContext se l'utente che visita ha un ruolo corrispondente e poi fare qualcosa con la richiesta (ad es. Inoltro, reindirizzamento) –

risposta

15

Quando Symfony2 elabora una richiesta, corrisponde al modello di URL con ciascun firewall definito in app/config/security.yml. Quando il pattern URL corrisponde a un pattern del firewall, Symfony2 crea alcuni oggetti listener e chiama il metodo handle di quegli oggetti. Se un listener restituisce un oggetto Response, il loop si interrompe e Symfony2 emette la risposta. La parte di autenticazione viene eseguita nei listener di autenticazione. Essi vengono creati da config definito abbinato firewall per esempio form_login, http_basic ecc Se l'utente non è autenticato ascoltatori poi autenticati creare un oggetto RedirectResponse per reindirizzare utente alla pagina di login. Per il tuo caso, puoi cheat creando un listener di autenticazione personalizzato e aggiungilo nel firewall della tua pagina protetta. implementazione del campione avrebbe seguito,

creare una classe Token,

namespace Your\Namespace; 

use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; 

class MyToken extends AbstractToken 
{ 
    public function __construct(array $roles = array()) 
    { 
     parent::__construct($roles); 
    } 

    public function getCredentials() 
    { 
     return ''; 
    } 
} 

creare una classe che implementa AuthenticationProviderInterface. Per il listener form_login si autentica con il dato UserProvider. In questo caso non farà nulla.

namespace Your\Namespace; 

use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; 
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; 
use Acme\BaseBundle\Firewall\MyToken; 

class MyAuthProvider implements AuthenticationProviderInterface 
{ 

    public function authenticate(TokenInterface $token) 
    { 
     if (!$this->supports($token)) { 
      return null; 
     } 

     throw new \Exception('you should not get here'); 
    } 

    public function supports(TokenInterface $token) 
    { 
     return $token instanceof MyToken; 
    } 

Creare una classe del punto di ingresso. L'ascoltatore creerà un RedirectResponse da questa classe.

namespace Your\Namespace; 

use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\Security\Core\Exception\AuthenticationException; 
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; 
use Symfony\Component\Security\Http\HttpUtils; 


class MyAuthenticationEntryPoint implements AuthenticationEntryPointInterface 
{ 
    private $httpUtils; 
    private $redirectPath; 

    public function __construct(HttpUtils $httpUtils, $redirectPath) 
    { 
     $this->httpUtils = $httpUtils; 
     $this->redirectPath = $redirectPath; 
    } 

    /** 
    * {@inheritdoc} 
    */ 
    public function start(Request $request, AuthenticationException $authException = null) 
    { 
     //redirect action goes here 
     return $this->httpUtils->createRedirectResponse($request, $this->redirectPath); 
    } 

Creare una classe di ascolto. Qui implementerai la tua logica di reindirizzamento.

namespace Your\Namespace; 

use Symfony\Component\Security\Http\Firewall\ListenerInterface; 
use Symfony\Component\HttpKernel\Event\GetResponseEvent; 
use Symfony\Component\Security\Core\SecurityContextInterface; 
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; 

class MyAuthenticationListener implements ListenerInterface 
{ 
    private $securityContext; 
    private $authenticationEntryPoint; 


    public function __construct(SecurityContextInterface $securityContext, AuthenticationEntryPointInterface $authenticationEntryPoint) 
    { 
     $this->securityContext = $securityContext; 
     $this->authenticationEntryPoint = $authenticationEntryPoint; 
    } 

    public function handle(GetResponseEvent $event) 
    { 
     $token = $this->securityContext->getToken(); 
     $request = $event->getRequest(); 
     if($token === null){ 
      return; 
     } 

     //add your logic 
     $redirect = // boolean value based on your logic 

     if($token->isAuthenticated() && $redirect){ 

      $response = $this->authenticationEntryPoint->start($request); 
      $event->setResponse($response); 
      return; 
     } 
    } 

} 

Creare i servizi.

<?xml version="1.0" ?> 
<container xmlns="http://symfony.com/schema/dic/services" 
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> 

    <services> 

     <service id="my_firewall.security.authentication.listener" 
       class="Your\Namespace\MyAuthenticationListener" 
       parent="security.authentication.listener.abstract" 
       abstract="true"> 
      <argument type="service" id="security.context" /> 
      <argument /> <!-- Entry Point --> 
     </service> 

     <service id="my_firewall.entry_point" class="Your\Namespace\MyAuthenticationEntryPoint" public="false" ></service> 

     <service id="my_firewall.auth_provider" class="Your\Namespace\MyAuthProvider" public="false"></service> 
    </services> 

</container> 

Registrare l'ascoltatore. Creare una cartella denominata Security/Factory nella cartella DependencyInjection. Quindi creare la classe di fabbrica.

namespace Your\Bundle\DependencyInjection\Security\Factory; 

use Symfony\Component\DependencyInjection\ContainerBuilder; 
use Symfony\Component\DependencyInjection\Reference; 
use Symfony\Component\DependencyInjection\DefinitionDecorator; 
use Symfony\Component\DependencyInjection\Definition; 
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; 
use Symfony\Component\Config\Definition\Builder\NodeDefinition; 

class MyFirewallFactory implements SecurityFactoryInterface 
{ 

    public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) 
    { 
     $provider = 'my_firewall.auth_provider.'.$id; 
     $container->setDefinition($provider, new DefinitionDecorator('my_firewall.auth_provider')); 

     // entry point 
     $entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPoint); 

     // listener 
     $listenerId = 'my_firewall.security.authentication.listener'.$id; 
     $listener = $container->setDefinition($listenerId, new DefinitionDecorator('my_firewall.security.authentication.listener')); 
     $listener->replaceArgument(1, new Reference($entryPointId)); 
     return array($provider, $listenerId, $entryPointId); 
    } 

    public function getPosition() 
    { 
     return 'pre_auth'; 
    } 

    public function getKey() 
    { 
     return 'my_firewall'; //the listener name 
    } 

    protected function getListenerId() 
    { 
     return 'my_firewall.security.authentication.listener'; 
    } 

    public function addConfiguration(NodeDefinition $node) 
    { 
     $node 
      ->children() 
       ->scalarNode('redirect_path')->end() 
      ->end() 
      ; 
    } 

    protected function createEntryPoint($container, $id, $config, $defaultEntryPointId) 
    { 
     $entryPointId = 'my_firewall.entry_point'.$id; 
     $container 
      ->setDefinition($entryPointId, new DefinitionDecorator('my_firewall.entry_point')) 
      ->addArgument(new Reference('security.http_utils')) 
      ->addArgument($config['redirect_path']) 
      ; 
     return $entryPointId; 
    } 

} 

Poi, nel tuo NamespaceBundle.php della cartella fascio aggiungere il seguente codice.

public function build(ContainerBuilder $builder){ 
    parent::build($builder); 
    $extension = $builder->getExtension('security'); 
    $extension->addSecurityListenerFactory(new Security\Factory\MyFirewallFactory()); 
} 

L'ascoltatore di autenticazione è stato creato, phew :). Ora nel tuo app/config/security.yml fai quanto segue.

api_area: 
    pattern: ^/secured/ 
    provider: fos_userbundle 
    form_login: 
    check_path: /login_check 
    login_path: /login 
    csrf_provider: form.csrf_provider 
    my_firewall: 
    redirect_path: /beta 
    logout: true 
    anonymous: true 
+1

Phew, bella risposta! +1 – halfer

0

Non so se questo è il metodo corretto ma si può provare il seguente

/vendor/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php ha un metodo handleRaw che converte una richiesta in una risposta. L'oggetto richiesta è accessibile da lì. Puoi verificare se il cliente ha richiesto di accedere alla pagina protetta. Se è così, è possibile impostare manualmente il controller come

$request->attributes->set('_controller','your\Bundle\SecureBundle\Controller\SecureController::secureAction'); 

Un'altra soluzione potrebbe essere quella di impostare una sessione se l'utente tenta di accedere a una pagina protetta e controllare lo stesso all'interno del vostro controller

Ancora una volta, questo potrebbe non è il metodo corretto ma è possibile una soluzione alternativa