发布于 2015-08-27 16:49:43 | 146 次阅读 | 评论: 0 | 来源: 网络整理
In the security chapter, you can see how to
secure a controller by requesting
the security.authorization_checker
service from the Service Container and
checking the current user’s role:
// ...
use SymfonyComponentSecurityCoreExceptionAccessDeniedException;
public function helloAction($name)
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
// ...
}
You can also secure any service by injecting the security.authorization_checker
service into it. For a general introduction to injecting dependencies into
services see the 服务容器(Service Container) chapter of the book. For
example, suppose you have a NewsletterManager
class that sends out emails
and you want to restrict its use to only users who have some
ROLE_NEWSLETTER_ADMIN
role. Before you add security, the class looks
something like this:
// src/AppBundle/Newsletter/NewsletterManager.php
namespace AppBundleNewsletter;
class NewsletterManager
{
public function sendNewsletter()
{
// ... where you actually do the work
}
// ...
}
Your goal is to check the user’s role when the sendNewsletter()
method is
called. The first step towards this is to inject the security.authorization_checker
service into the object. Since it won’t make sense not to perform the security
check, this is an ideal candidate for constructor injection, which guarantees
that the authorization checker object will be available inside the NewsletterManager
class:
// src/AppBundle/Newsletter/NewsletterManager.php
// ...
use SymfonyComponentSecurityCoreAuthorizationAuthorizationCheckerInterface;
class NewsletterManager
{
protected $authorizationChecker;
public function __construct(AuthorizationCheckerInterface $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
}
// ...
}
Then in your service configuration, you can inject the service:
# app/config/services.yml
services:
newsletter_manager:
class: "AppBundleNewsletterNewsletterManager"
arguments: ["@security.authorization_checker"]
<!-- app/config/services.xml -->
<services>
<service id="newsletter_manager" class="AppBundleNewsletterNewsletterManager">
<argument type="service" id="security.authorization_checker"/>
</service>
</services>
// app/config/services.php
use SymfonyComponentDependencyInjectionDefinition;
use SymfonyComponentDependencyInjectionReference;
$container->setDefinition('newsletter_manager', new Definition(
'AppBundleNewsletterNewsletterManager',
array(new Reference('security.authorization_checker'))
));
The injected service can then be used to perform the security check when the
sendNewsletter()
method is called:
namespace AppBundleNewsletter;
use SymfonyComponentSecurityCoreAuthorizationAuthorizationCheckerInterface;
use SymfonyComponentSecurityCoreExceptionAccessDeniedException;
// ...
class NewsletterManager
{
protected $authorizationChecker;
public function __construct(AuthorizationCheckerInterface $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
}
public function sendNewsletter()
{
if (false === $this->authorizationChecker->isGranted('ROLE_NEWSLETTER_ADMIN')) {
throw new AccessDeniedException();
}
// ...
}
// ...
}
If the current user does not have the ROLE_NEWSLETTER_ADMIN
, they will
be prompted to log in.
You can also secure method calls in any service with annotations by using the optional JMSSecurityExtraBundle bundle. This bundle is not included in the Symfony Standard Distribution, but you can choose to install it.
To enable the annotations functionality, tag
the service you want to secure with the security.secure_service
tag
(you can also automatically enable this functionality for all services, see
the sidebar below):
# app/services.yml
# ...
services:
newsletter_manager:
# ...
tags:
- { name: security.secure_service }
<!-- app/services.xml -->
<!-- ... -->
<services>
<service id="newsletter_manager" class="AppBundleNewsletterNewsletterManager">
<!-- ... -->
<tag name="security.secure_service" />
</service>
</services>
// app/services.php
use SymfonyComponentDependencyInjectionDefinition;
use SymfonyComponentDependencyInjectionReference;
$definition = new Definition(
'AppBundleNewsletterNewsletterManager',
// ...
));
$definition->addTag('security.secure_service');
$container->setDefinition('newsletter_manager', $definition);
You can then achieve the same results as above using an annotation:
namespace AppBundleNewsletter;
use JMSSecurityExtraBundleAnnotationSecure;
// ...
class NewsletterManager
{
/**
* @Secure(roles="ROLE_NEWSLETTER_ADMIN")
*/
public function sendNewsletter()
{
// ...
}
// ...
}
注解
The annotations work because a proxy class is created for your class which performs the security checks. This means that, whilst you can use annotations on public and protected methods, you cannot use them with private methods or methods marked final.
The JMSSecurityExtraBundle also allows you to secure the parameters and return values of methods. For more information, see the JMSSecurityExtraBundle documentation.