Symfony 2.4, el libro oficial

13.5. Controlando el acceso mediante expresiones

Además de roles simples como ROLE_ADMIN, a partir de Symfony 2.4 el método isGranted() acepta como argumento expresiones complejas definidas mediante objetos de tipo Symfony\Component\ExpressionLanguage\Expression:

use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\ExpressionLanguage\Expression;
// ...

public function indexAction()
{
    if (!$this->get('security.context')->isGranted(new Expression(
        '"ROLE_ADMIN" in roles or (user and user.isSuperAdmin())'
    ))) {
        throw new AccessDeniedException();
    }

    // ...
}

En este ejemplo, si el usuario actual tiene el role ROLE_ADMIN o si el método isSuperAdmin() del objeto que representa al usuario devuelve el valor true, se permitirá el acceso. Ten en cuenta que la clase que representa a tus usuarios puede no tener definido el método isSuperAdmin(), ya que se trata de un método inventado para este ejemplo.

Consulta la documentación del componente ExpressionLanguage para conocer todos los detalles sobre su sintaxis.

Por otra parte, dentro de una expresión puedes hacer uso de las siguientes variables:

  • user, el objeto que representa al usuario conectado (o la cadena de texto anon si el usuario no está conectado).
  • roles, el array de roles del usuario, incluyendo (si están definidos) los roles heredados mediante la jerarquía de roles. En este array no se incluyen los roles de tipo IS_AUTHENTICATED_*.
  • object: el objeto (si está definido) que se pasa como segungo argumento del método isGranted.
  • token: el objeto del token del usuario.
  • trust_resolver: el objeto de tipo Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolverInterface. Normalmente, en vez de este objeto, se utilizan las funciones is_*() explicadas a continuación.

Además de estas variables, dentro de una expresión puedes hacer uso de las siguientes funciones:

  • is_authenticated: devuelve true si el usuario está autenticado mediante la opción Remember me o si ha introducido su usuario y contraseña.
  • is_anonymous: equivalente a usar IS_AUTHENTICATED_ANONYMOUSLY con la función isGranted.
  • is_remember_me: parecido, aunque no exactamente igual, a IS_AUTHENTICATED_REMEMBERED (ver detalles más adelante).
  • is_fully_authenticated: similar, aunque no exactamente igual, a IS_AUTHENTICATED_FULLY (ver detalles más adelante).
  • has_role: comprueba si el usuario dispone del role que se indica, por lo que es equivalente a una expresión como: 'ROLE_ADMIN' in roles.

13.5.1. Controlando el acceso en otros servicios

Aplicando una estrategia similar a la explicada en la sección anterior para los controladores, puedes proteger cualquier otro recurso de Symfony. Si por ejemplo dispones de un servicio que envía emails de parte de un usuario a otro usuario, puedes restringir el uso de esta clase a aquellos usuarios que tengan un role específico.

Consulta el artículo How to secure any Service or Method in your Application para obtener más información sobre cómo utilizar el componente de seguridad para proteger diferentes métodos y servicios de tu aplicación.

13.5.2. Controlando el acceso en las plantillas

Si quieres comprobar los roles de un usuario dentro de una plantilla, utiliza el helper is_granted():

{% if is_granted('ROLE_ADMIN') %}
    <a href="...">Delete</a>
{% endif %}
<?php if ($view['security']->isGranted('ROLE_ADMIN')): ?>
    <a href="...">Delete</a>
<?php endif; ?>

Nota Si utilizas esta función en una plantilla asociada a una URL que no está protegida por un firewall, se mostrará una excepción. Por eso es una buena idea definir un firewall que proteja todas las URL de la aplicación (como ya se explicó al principio de este capítulo).

A partir de la versión 2.4 de Symfony también es posible utilizar expresiones dentro de las plantillas:

{% if is_granted(expression(
    '"ROLE_ADMIN" in roles or (user and user.isSuperAdmin())'
)) %}
    <a href="...">Delete</a>
{% endif %}
<?php if ($view['security']->isGranted(new Expression(
    '"ROLE_ADMIN" in roles or (user and user.isSuperAdmin())'
))): ?>
    <a href="...">Delete</a>
<?php endif; ?>

13.5.3. Listas de control de acceso (ACL)

Imagina que has desarrollado un sistema de blog donde los usuarios pueden comentar tus artículos. Además, quieres que los usuarios puedan modificar sus propios comentarios pero no los de otros usuarios. Por último, quieres que el usuario admin pueda modificar cualquier comentario.

El componente de seguridad incluye un sistema de listas de control de acceso (ACL) que puedes utilizar cuando necesites controlar el acceso a las instancias de un objeto. Sin ACL puedes proteger tu sistema para que sólo determinados usuarios puedan editar los comentarios del blog en general. Pero con ACL puedes restringir o permitir el acceso comentario por comentario.

Para más información, consulta el artículo How to use Access Control Lists (ACLs).