アプリケーション内でサービスやメソッドをセキュアにする方法

セキュリティの章では、サービスコンテナの security.context サービスを要求して、ユーザの権限を調べることで、コントローラをセキュアにする(secure a controller)方法を参照することができます。

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

public function helloAction($name)
{
    if (false === $this->get('security.context')->isGranted('ROLE_ADMIN')) {
        throw new AccessDeniedException();
    }

    // ...
}

同じような方法を使用して security.context サービスを注入する(inject)することで、 全て のサービスをセキュアにすることができます。サービスの依存(dependencies)注入(inject)に関する、より一般的なイントロダクションとして、ガイドブックの サービスコンテナ の章を参照してください。例として、メール送信を行う ROLE_NEWSLETTER_ADMIN 権限を持ったユーザのみしか使用できない NewsletterManager クラスがあるとしましょう。セキュリティを追加する前は、このクラスは次のようになっています。

namespace Acme\HelloBundle\Newsletter;

class NewsletterManager
{

    public function sendNewsletter()
    {
        // where you actually do the work
    }

    // ...
}

sendNewsletter() メソッドが呼ばれた際に、ユーザの権限を調べるようにする必要があります。最初のステップとして、オブジェクトに security.context` サービスを注入(inject)します。セキュリティチェックとして 機能する 必要があるので、コンストラクタへの注入(injection)の理想的な候補として NewsletterManager 内で利用可能なセキュリティコンテキストオブジェクトを保証するようします。

namespace Acme\HelloBundle\Newsletter;

use Symfony\Component\Security\Core\SecurityContextInterface;

class NewsletterManager
{
    protected $securityContext;

    public function __construct(SecurityContextInterface $securityContext)
    {
        $this->securityContext = $securityContext;
    }

    // ...
}

サービスコンフィギュレーションで、サービスを注入(inject)することができます。

  • YAML
    # src/Acme/HelloBundle/Resources/config/services.yml
    parameters:
        newsletter_manager.class: Acme\HelloBundle\Newsletter\NewsletterManager
    
    services:
        newsletter_manager:
            class:     %newsletter_manager.class%
            arguments: [@security.context]
  • XML
    <!-- src/Acme/HelloBundle/Resources/config/services.xml -->
    <parameters>
        <parameter key="newsletter_manager.class">Acme\HelloBundle\Newsletter\NewsletterManager</parameter>
    </parameters>
    
    <services>
        <service id="newsletter_manager" class="%newsletter_manager.class%">
            <argument type="service" id="security.context"/>
        </service>
    </services>
    
  • PHP
    // src/Acme/HelloBundle/Resources/config/services.php
    use Symfony\Component\DependencyInjection\Definition;
    use Symfony\Component\DependencyInjection\Reference;
    
    $container->setParameter('newsletter_manager.class', 'Acme\HelloBundle\Newsletter\NewsletterManager');
    
    $container->setDefinition('newsletter_manager', new Definition(
        '%newsletter_manager.class%',
        array(new Reference('security.context'))
    ));
    

注入された(injected)サービスは、 sendNewsletter() メソッドが呼ばれたときのセキュリティチェックとして機能として使用することができます。

namespace Acme\HelloBundle\Newsletter;

use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\SecurityContextInterface;
// ...

class NewsletterManager
{
    protected $securityContext;

    public function __construct(SecurityContextInterface $securityContext)
    {
        $this->securityContext = $securityContext;
    }

    public function sendNewsletter()
    {
        if (false === $this->securityContext->isGranted('ROLE_NEWSLETTER_ADMIN')) {
            throw new AccessDeniedException();
        }

        //--
    }

    // ...
}

ユーザが ROLE_NEWSLETTER_ADMIN 権限を持っていなければ、ログインを促します。

アノテーションを使用してメソッドをセキュアにする

オプションの JMSSecurityExtraBundle バンドルを使用することで、アノテーションを使ってどんなサービスのメソッド呼び出しもセキュアにすることができます。このバンドルは Symfony2 Standard Distribution に付いてきます。

アノテーションの機能を有効にするには、セキュアにしたいサービスに security.secure_service タグ tag を付けてください(下のサイドバー sidebar を参考に全てのサービスの機能を自動的に有効にすることもできます)。

  • YAML
    # src/Acme/HelloBundle/Resources/config/services.yml
    # ...
    
    services:
        newsletter_manager:
            # ...
            tags:
                -  { name: security.secure_service }
    
  • XML
    <!-- src/Acme/HelloBundle/Resources/config/services.xml -->
    <!-- ... -->
    
    <services>
        <service id="newsletter_manager" class="%newsletter_manager.class%">
            <!-- ... -->
            <tag name="security.secure_service" />
        </service>
    </services>
    
  • PHP
    // src/Acme/HelloBundle/Resources/config/services.php
    use Symfony\Component\DependencyInjection\Definition;
    use Symfony\Component\DependencyInjection\Reference;
    
    $definition = new Definition(
        '%newsletter_manager.class%',
        array(new Reference('security.context'))
    ));
    $definition->addTag('security.secure_service');
    $container->setDefinition('newsletter_manager', $definition);
    

これでアノテーションを使用して上記と同じ実装をすることができます。

namespace Acme\HelloBundle\Newsletter;

use JMS\SecurityExtraBundle\Annotation\Secure;
// ...

class NewsletterManager
{

    /**
     * @Secure(roles="ROLE_NEWSLETTER_ADMIN")
     */
    public function sendNewsletter()
    {
        //--
    }

    // ...
}

Note

セキュリティチェックとして機能するクラスのプロクシクラスを作成すれば、アノテーションは動作するようになります。アノテーションは、public と protected なメソッドには使用することができますが、 private なメソッドや final 指定のメソッドには使用することはできません。

JMSSecurityExtraBundle を使用すれば、パラメータとメソッドの返り値をセキュアにすることができます。詳細は、 JMSSecurityExtraBundle のドキュメントを参照してください。

このページのコンテンツ

ソース



クイックリンク

コメントリスト


ご質問や翻訳不備等お気軽にコメントください。


現在、翻訳が古くなっている箇所が多くあります。1箇所、1行などほんの少量でもかまいませんので、ドキュメント翻訳にご協力いただける方を募集しています。日本 Symfony ユーザー会メーリングリストまでご連絡ください。