Symfony2 - защищать определенные HTTP-методы для URL-адреса
Итак, я пытаюсь создать RESTful API в Symfony2, но у меня проблема с безопасностью.
Скажем, например, я хочу создать нового пользователя с моим API. Я сделаю следующий запрос:
POST /api/v1/users.json HTTP/1.1
Этот URL должен быть доступен всем клиентам, поэтому аутентификации не требуется. Но, допустим, я хочу запросить список всех пользователей. Согласно идее REST, я должен сделать запрос GET:
GET /api/v1/users.json HTTP/1.1
Конечно, я не хочу, чтобы этот список был доступен всем, поэтому мне нужно его закрепить в Symfony2. Конечно, следующее не будет работать, поскольку оно защищает весь шаблон URL, а не 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 }
Итак, существует ли секретный параметр для директивы access_control
, которая защищает метод HTTP? Или есть другой способ? Я попытался использовать JMSSecurityExtraBundle:
/**
* @Secure(roles="ROLE_ADMIN")
*/
public function listAction()
{
return new Response('Cubilon\\SocialPortal\\APIBundle\\Controller\\UserController', 200);
}
Какой должен обеспечить этот метод, но он не работает...
Как я могу защитить определенный HTTP-метод в сочетании с шаблоном URL?
EDIT:
Итак, как я уже сказал ниже, я исправил его с помощью JMSSecurityExtraBundle. Я определил службы, которые хочу защитить в Ресурсах /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>
И затем я защитил каждое действие в 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)
{
// ...
}
}
В каждом защищенном действии я проверяю учетные данные защищенного пользователя (независимо от того, является ли аутентифицированное имя пользователя таким же, как запрошенное имя пользователя и т.д.).
Ответы
Ответ 1
Я знаю, что уже поздно, но если кто-то наткнется на эти вопросы, вот как обеспечить безопасность для каждого запроса по HTTP-методу (см. Документация безопасности Symfony):
# 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 }
Соблюдайте порядок, в котором вы устанавливаете правила.
Ответ 2
В соответствии с справочником по безопасности, вы не можете защитить URL по методу.
Не лучший способ, но вы можете сделать это, в действии:
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);
}
Или вы можете создать новый прослушиватель событий ядра, который будет проверять метод и пользователя ROLE как мой предыдущий пример, но распространяется на все действия! ^^
Ответ 3
Остерегайтесь, есть 2 вещи:
- брандмауэр (аутентификация)
- контроль доступа (авторизация)
Принятый ответ показывает, как ограничить правило контроля доступа методом HTTP, но вот как ограничить правило брандмауэра методом HTTP:
security:
firewalls:
secured_area:
methods: [POST, PUT]
Обратите внимание, что эта функция была добавлена в Symfony 2.5.
Как показано в другом ответе, вот как ограничить правило контроля доступа методом HTTP:
security:
# ...
access_control:
- { path: ^/api/v1/users.json, roles: ROLE_ADMIN, methods: [POST, PUT] }