支付宝扫一扫付款
微信扫一扫付款
(微信为保护隐私,不显示你的昵称)
在security文档中,你可以看到,如何通过从服务容器中请求 security.authorization_checker
服务并检查当前用户的角色(role),来 保护一个控制器:
1 2 3 4 5 6 7 8 9 | // ...
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
public function helloAction($name)
{
$this->denyAccessUnlessGranted('ROLE_ADMIN');
// ...
} |
你也可以通过把 security.authorization_checker
服务注入到 任意 服务来保护它。把依赖注入到服务的基本知识,参考 服务容器 一文。例如,假设你有一个 NewsletterManager
类,用于发送邮件,你希望将它的使用限制在那些拥有 ROLE_NEWSLETTER_ADMIN
role的用户。在添加security之前,类看起来是这个样子:
1 2 3 4 5 6 7 8 9 10 11 12 | // src/AppBundle/Newsletter/NewsletterManager.php
namespace AppBundle\Newsletter;
class NewsletterManager
{
public function sendNewsletter()
{
// ... where you actually do the work / 你在此处真正做事
}
// ...
} |
你的目标,是在 sendNewsletter()
方法被调用时,去检查用户的role。迈出的第一步,是向该对象注入 security.authorization_checker
服务。若 不 进行安全检查,此举将会失去意义,这是构造器注入(constructor injection)的理想场合,它确保authorization checker对象在 NewLetterManager
类中可用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // src/AppBundle/Newsletter/NewsletterManager.php
// ...
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
class NewsletterManager
{
protected $authorizationChecker;
public function __construct(AuthorizationCheckerInterface $authorizationChecker)
{
$this->authorizationChecker = $authorizationChecker;
}
// ...
} |
接下来,在你的服务定义中注入服务:
1 2 3 4 5 | # app/config/services.yml
services:
newsletter_manager:
class: AppBundle\Newsletter\NewsletterManager
arguments: ['@security.authorization_checker'] |
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<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="newsletter_manager" class="AppBundle\Newsletter\NewsletterManager">
<argument type="service" id="security.authorization_checker"/>
</service>
</services>
</container> |
1 2 3 4 5 6 7 8 | // app/config/services.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
$container->setDefinition('newsletter_manager', new Definition(
'AppBundle\Newsletter\NewsletterManager',
array(new Reference('security.authorization_checker'))
)); |
当 sendNewsletter()
方法被调用时,被注入服务将被用于去执行安全检查(security check):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | namespace AppBundle\Newsletter;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
// ...
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();
}
// ...
}
// ...
} |
如果当前用户没有 ROLE_NEWSLETTER_ADMIN
,他们会被提示登录。
你也可以使用可选的 JMSSecurityExtraBundle bundle,在任意服务中,使用annotation注释来保护method calls(类的方法调用)。这个bundle没有包含在Symfony标准版中,但你可以选择安装它。
要开启annotation功能,使用 security.secure_service
tag来对你想要保护的服务来 打标签您想保护的服务(你还可以为所有服务自动开启此功能,见本文底部“+”区块):
1 2 3 4 5 6 | # app/config/services.yml
services:
newsletter_manager:
class: AppBundle\Newsletter\NewsletterManager
tags:
- { name: security.secure_service } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | <!-- app/config/services.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<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="newsletter_manager" class="AppBundle\Newsletter\NewsletterManager">
<tag name="security.secure_service" />
</service>
</services>
</container> |
1 2 3 4 5 6 7 8 9 10 | // app/config/services.php
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
$definition = new Definition(
'AppBundle\Newsletter\NewsletterManager',
// ...
));
$definition->addTag('security.secure_service');
$container->setDefinition('newsletter_manager', $definition); |
然后你就可以使用annotation来实现相同的结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | namespace AppBundle\Newsletter;
use JMS\SecurityExtraBundle\Annotation\Secure;
// ...
class NewsletterManager
{
/**
* @Secure(roles="ROLE_NEWSLETTER_ADMIN")
*/
public function sendNewsletter()
{
// ...
}
// ...
} |
annotations 注释能工作,是因为为你的“要执行安全检查的类”创建了一个代理类(proxy class)。这意味着,你只能在 public 和 protected 方法中使用annotations ,而不能在 private 或标记成 final 的方法中使用它们。
JMSSecurityExtraBundle 还允许你保护方法的参数和返回值。参考 JMSSecurityExtraBundle 文档以了解更多。
本文,包括例程代码在内,采用的是 Creative Commons BY-SA 3.0 创作共用授权。