2012-04-10 30 views
8

Tôi muốn kiểm tra từ bên trong một bộ điều khiển nếu đó là một trang được bảo mật hay không. Cách thực hiện việc này?Symfony2: cách kiểm tra xem hành động có được bảo mật không?

trường hợp sử dụng của tôi là như sau:

  • Người dùng có thể đăng ký và đăng nhập
  • Nếu anh ta đăng nhập vào và cố gắng truy cập vào một trang bảo đảm, ông sẽ được chuyển hướng đến một trang "phiên bản beta" cho đến khi cuối tháng Sáu.
  • Nếu anh ta cố gắng truy cập một trang bình thường (không được bảo mật), anh ấy sẽ có thể truy cập trang đó mà không cần chuyển hướng.

Cảm ơn sự giúp đỡ của bạn!

Aurel

+0

Tôi không chắc bạn đang cố gắng đạt được điều gì. Khi người dùng nhập URL (hoặc đang được chuyển hướng đến) action ** hành động đó được bảo mật hoặc không được bảo mật **. Bộ điều khiển không thể có nhiều hành động (bảo mật và không được bảo mật) với cùng tên, vì rõ ràng là tên phương thức. Tuy nhiên, bạn có thể yêu cầu SecureContext nếu người dùng truy cập có vai trò tương ứng và sau đó làm điều gì đó với yêu cầu (ví dụ: chuyển tiếp, chuyển hướng) –

Trả lời

15

Khi Symfony2 xử lý yêu cầu, nó khớp với mẫu url với mỗi tường lửa được xác định trong app/config/security.yml. Khi mẫu url khớp với mẫu tường lửa Symfony2 tạo một số đối tượng nghe và gọi phương thức handle của các đối tượng đó. Nếu bất kỳ trình lắng nghe nào trả về đối tượng Response thì ngắt vòng lặp và Symfony2 sẽ trả về kết quả. Phần xác thực được thực hiện trong trình lắng nghe xác thực. Chúng được tạo từ cấu hình được xác định trong tường lửa phù hợp, ví dụ: form_login, http_basic v.v. Nếu người dùng không được xác thực thì người nghe được xác thực tạo đối tượng RedirectResponse để chuyển hướng người dùng đến trang đăng nhập. Trong trường hợp của bạn, bạn có thể gian lận bằng cách tạo trình xử lý xác thực tùy chỉnh và thêm nó vào tường lửa trang được bảo mật của mình. Triển khai mẫu sẽ được sau,

Tạo một lớp 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 ''; 
    } 
} 

Tạo một lớp mà thực hiện AuthenticationProviderInterface. Đối với người nghe form_login, người nghe sẽ xác thực với số UserProvider đã cho. Trong trường hợp này nó sẽ không làm gì cả.

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; 
    } 

Tạo lớp điểm nhập. Người nghe sẽ tạo một số RedirectResponse từ lớp này.

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); 
    } 

Tạo lớp người nghe. Ở đây bạn sẽ thực hiện logic chuyển hướng của bạn.

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; 
     } 
    } 

} 

Tạo dịch vụ.

<?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> 

Đăng ký người nghe. Tạo thư mục có tên Security/Factory trong nhóm của bạn DependencyInjection thư mục. Sau đó tạo lớp nhà máy.

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; 
    } 

} 

Sau đó, trong NamespaceBundle.php của thư mục gói, hãy thêm mã sau đây.

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

Trình nghe xác thực được tạo, phew :). Bây giờ trong số app/config/security.yml của bạn làm theo.

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, câu trả lời hay! +1 – halfer

0

Tôi không biết nếu điều này là phương pháp đúng Nhưng bạn có thể thử cách sau

/vendor/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php có một phương pháp handleRaw chuyển đổi yêu cầu thành phản hồi. Đối tượng yêu cầu có thể truy cập từ đó. Bạn có thể kiểm tra xem khách hàng có yêu cầu truy cập trang được bảo mật hay không. Nếu vậy, bạn có thể tự thiết lập các điều khiển như

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

Một giải pháp khác sẽ được thiết lập một phiên làm việc nếu người dùng cố gắng truy cập vào một trang bảo đảm và kiểm tra cho cùng một bên điều khiển của bạn

Một lần nữa, sức mạnh này không phải là phương pháp chính xác nhưng có thể là giải pháp có thể

Các vấn đề liên quan