2012-01-25 8 views
10

Quindi, sto cercando di creare un'API RESTful in Symfony2, ma sto riscontrando un problema con la sicurezza.Symfony2 - Protezione di metodi HTTP specifici per l'URL

Diciamo, per esempio, voglio creare un nuovo utente con la mia API. Farò la seguente richiesta:

POST /api/v1/users.json HTTP/1.1

Questo URL deve essere accessibile da tutti i clienti, quindi non c'è autenticazione richiesta. Ma diciamo che voglio richiedere un elenco di tutti gli utenti. Secondo l'idea REST, dovrei fare una richiesta GET:

GET /api/v1/users.json HTTP/1.1

Naturalmente, non voglio questa lista per essere accessibile da tutti, quindi dovrò fissarlo in Symfony2. Quanto segue non funziona, naturalmente, dal momento che protegge l'intero modello di URL, e non il metodo HTTP:

security: 
    encoders: 
     Symfony\Component\Security\Core\User\User: plaintext 

    role_hierarchy: 
     ROLE_ADMIN:  ROLE_USER 
     ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] 

    providers: 
     in_memory: 
      users: 
       user: { password: userpass, roles: [ 'ROLE_USER' ] } 
       admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] } 

    firewalls: 
     secured_area: 
      pattern: ^/ 
      anonymous: ~ 
      http_basic: 
       realm: "Social Portal API" 

    access_control: 
     - { path: /api/v1/users.json, roles: ROLE_ADMIN } 

Quindi, c'è un parametro segreto per la direttiva access_control che fissa il metodo HTTP? O c'è un altro modo? Ho cercato di utilizzare il JMSSecurityExtraBundle:

/** 
* @Secure(roles="ROLE_ADMIN") 
*/ 
public function listAction() 
{ 
    return new Response('Cubilon\\SocialPortal\\APIBundle\\Controller\\UserController', 200); 
} 

Che dovrebbe garantire questo metodo, ma non ha funzionato ...

Come posso ottenere un certo metodo HTTP in combinazione con un modello di URL?

EDIT:

Quindi, come ho detto sotto la risposta qui sotto, ho fissato utilizzando il JMSSecurityExtraBundle. Ho definito i servizi che vogliono assicurarsi in Risorse/config/services.xml:

# Resources/config/services.xml 
<?xml version="1.0" encoding="utf-8"?> 
<services> 
    <service id="user_controller" class="Cubilon\SocialPortal\APIBundle\Controller\UserController"> 
     <tag name="security.secure_service" /> 
    </service> 
</services> 

E poi fissato ogni azione di conseguenza nel UserController:

# Controller/UserController.php 
<?php 
namespace Cubilon\SocialPortal\APIBundle\Controller\UserController; 

use Symfony\Bundle\FrameworkBundle\Controller\Controller; 
use JMS\SecurityExtraBundle\Annotation\Secure; 

class UserController extends Controller 
{ 
    public function createAction($_format) 
    { 
     // ... 
    } 

    /** 
    * @Secure(roles="ROLE_USER, ROLE_ADMIN") 
    */ 
    public function readAction($username, $_format) 
    { 
     // ... 
    } 

    /** 
    * @Secure(roles="ROLE_USER, ROLE_ADMIN") 
    */ 
    public function updateAction($username, $_format) 
    { 
     // ... 
    } 

    /** 
    * @Secure(roles="ROLE_USER, ROLE_ADMIN") 
    */ 
    public function deleteAction($username, $_format) 
    { 
     // ... 
    } 
} 

In ogni azione messa in sicurezza verifico le credenziali dell'utente protetto (se il nome utente autenticato è lo stesso del nome utente richiesto e così via).

risposta

12

So che è in ritardo, ma se qualcuno inciampa su questa domanda qui è come garantire per una richiesta per il metodo HTTP (si veda il Symfony security documentation):

# app/config/security.yml 
security: 
    # ... 
    access_control: 
     - { path: ^/api/v1/users.json, roles: ROLE_ADMIN, methods: [POST, PUT] } 
     - { path: /api/v1/users.json, roles: ROLE_ADMIN } 

Fare attenzione l'ordine in cui si imposta le regole.

4

In base allo security reference book, non è possibile proteggere un URL in base al metodo.

Non è il miglior modo, ma si può fare così, nell'azione:

public function listAction(Request $request) 
{ 
    if ($request->getMethod() == 'GET' && !$this->get('security.context')->isGranted('ROLE_ADMINISTRATOR')) { 
     throw $this->createNotFoundException("This page doesn't exist."); // forward a 404, or a message in a json... 
    } 

    return new Response('Cubilon\\SocialPortal\\APIBundle\\Controller\\UserController', 200); 
} 

Oppure si può creare un nuovo kernel event listener che controllerà il metodo e il ruolo utente come il mio precedente esempio, ma si estendono a tutte le azioni! ^^

+0

ho finalmente risolto utilizzando il JMSSecurityExtraBundle come ho cercato prima, ma io in qualche modo didn Non leggere che dovevi specificare anche la lezione. –

+2

Ramon: potresti ampliare il tuo commento? Come si specifica la classe? –

+0

Ho modificato la mia domanda per chiarire come l'ho risolta. –

2

Attenzione, ci sono 2 cose:

  • firewall (autenticazione)
  • di controllo di accesso (autorizzazione)

La risposta accettata mostra come limitare una regola di controllo di accesso a un HTTP metodo, ma ecco come limitare una regola del firewall a un metodo HTTP:

security: 
    firewalls: 
     secured_area: 
      methods: [POST, PUT] 

Si noti che questa funzione è stata aggiunta in Symfony 2.5.

Come mostrato in altra risposta, ecco come ad limitare una regola di controllo di accesso a un metodo HTTP:

security: 
    # ... 
    access_control: 
     - { path: ^/api/v1/users.json, roles: ROLE_ADMIN, methods: [POST, PUT] } 
Problemi correlati