2011-10-13 13 views
6

Tengo una situación en la que necesito ejecutar algún código si el usuario intenta acceder a una URL protegida y es no autenticado/autorizado.¿Es posible ver si una URL/ruta está protegida detrás del firewall de forma programática?

De forma predeterminada, Symfony maneja usuarios no autenticados al redireccionar o reenviar al usuario a un formulario de inicio de sesión. Me gustaría evitar que esto suceda si el método de solicitud es POST, y en su lugar echo un objeto JSON.

La mejor manera que puedo pensar para manejar esto es para crear un escucha personalizado que escucha el caso kernel.request y comprueba dos cosas:

  • comprueba si el método de la petición es POST
  • comprueba si el el usuario es autenticado totalmente

Si se trata de una petición POST, y el usuario no está autenticado por completo, me gustaría repetir un objeto JSON.

Pero mi oyente (esperadamente) está disparando para todas las solicitudes. Me gustaría limitarlo a comprobar solo si la solicitud es para una URL protegida por el firewall. ¿Es posible verificar esto programáticamente?

que también tienen una persistente sospecha de que hay una manera más sencilla de hacer esto, pero no puede entenderlo, así que si alguien tiene algún consejo, me encantaría escucharlos :)

Editar
@Problematic: el motivo para verificar únicamente las solicitudes cortadas es porque tengo algunas solicitudes que no tienen cortafuegos, y si mi código se activa, recibiré el objeto JSON antes mencionado en lugar de la respuesta real de la solicitud.

En este momento, si no estoy conectado y realizo una solicitud POST al api/get/something (que está detrás del firewall), Symfony devuelve el código HTML que describe la página de inicio de sesión. En cambio, quiero simplemente hacer un eco de algo como {error: 'User is not authorized'}. Pero solo quiero que esto suceda para las solicitudes POST.

+0

¿Cuál es el motivo de solo verificar las solicitudes de firewall? – Problematic

+0

@Problematic, vea mi edición –

Respuesta

3

Creo que iba por este camino equivocado. Quería saber si una URL estaba detrás del firewall, pero creo que debería haber estado tratando de averiguar si el usuario actual fue autorizado para la solicitud. En esencia, saber que a un usuario se le niega el acceso a una URL significa que la URL debe estar detrás de un firewall, de lo contrario, el acceso no podría haber sido denegado.

Teniendo esto en cuenta, pude obtener el resultado final que quería. Es bastante sencillo una vez que se da cuenta de cómo funciona el mecanismo de seguridad ...

  • Symfony\Component\Security\Http\Firewall detecta el evento kernel.request
  • Firewall entonces llama a un número de detectores de eventos que se registran en security.yml
  • Si alguna violación de seguridad (es decir, un usuario que intenta acceder a algo sin haber iniciado sesión) se detecta, se lanza un AccessDeniedException y se envía el evento kernel.exception.
  • Symfony/Component/Security/Http/Firewall/ExceptionListener escucha el evento y dispara su método onKernelException que decide cuál es el siguiente paso.En mi caso, sería iniciar el proceso de autenticación

Desde que comenzó el proceso de autenticación es lo que quería evitar, escribí mi propio detector de eventos que intercepta kernel.exception antes de Symfony ExceptionListener hace. Di mi detector de eventos en una prioridad de 1.

Este es el método que escribí:

public function handleException(GetResponseForExceptionEvent $event) { 
     $exception = $event->getException(); 
     $request = $event->getRequest(); 
     if ($request->getMethod() == 'POST') { 
      if ($exception instanceof AccessDeniedException) { 
       $response = new Response({err: 'not logged in'}); 
       $event->setResponse($response); 
      } 
     } 
    } 

Mientras el usuario no está autorizado, y el método de la petición es POST, se devuelve un objeto JSON (que también detiene la propagación del evento) en lugar del HTML de la página de inicio de sesión. De lo contrario, otros oyentes de kernel.exception reaccionarán y Symfony podrá hacer su trabajo.

Por lo tanto, la pregunta original permanece sin respuesta, pero creo que se podría lograr al verificar si un usuario tiene acceso a una acción. Symfony\Component\Security\Core\Authorization\AccessDecisionManager parece que sería útil para esto.

Editar
no sé si este método sólo se maneja los usuarios que no han iniciado sesión. No he probado todavía, pero creo que también se disparará si un (conectado) el usuario intenta acceder a una acción que requiere un rol que no se le ha otorgado. Si esto causa un problema, trataría de modificarlo para usar el método Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverisFullFledged($token) para que solo se preocupe por los usuarios que no han iniciado sesión.

+0

Si está enviando una respuesta json, debe agregar un cheque para ver si se trata de una solicitud ajax usando esto: $ request-> isXmlHttpRequest(). Esto es lo que usé para convertir el método de autenticación predeterminado en un método ajax. – HappyDeveloper

+0

@HappyDeveloper gracias por la sugerencia, pero todavía estoy usando un formulario de inicio de sesión regular. Solo necesitaba reaccionar de manera diferente si se realizaba una solicitud POST a las acciones protegidas y el usuario no había iniciado sesión. –

Cuestiones relacionadas