Symfony:为拒绝访问的安全投票者提供消息?
我正在为一个API做安全性方面的工作。我在每个请求中检查的内容包括:Symfony:为拒绝访问的安全投票者提供消息?,symfony,Symfony,我正在为一个API做安全性方面的工作。我在每个请求中检查的内容包括: 用户的IP地址是否已列入白名单以供访问 用户的帐户是否已过期 是否超出了用户当天的费率限制 似乎我应该使用一个安全投票者,可能每个投票者一个,当访问检查失败时返回VoterInterface::ACCESS\u DENIED 但是,我想在API响应中向用户提供一条消息,该消息提供一些指示,说明他们的请求被拒绝的原因。我不能对一个安全选民这样做 我当前的解决方法是侦听内核控制器事件,执行我的访问检查,然后在检查失败时抛出带有我的
VoterInterface::ACCESS\u DENIED
但是,我想在API响应中向用户提供一条消息,该消息提供一些指示,说明他们的请求被拒绝的原因。我不能对一个安全选民这样做
我当前的解决方法是侦听内核控制器
事件,执行我的访问检查,然后在检查失败时抛出带有我的特定消息的显式AccessDeniedException
这是处理这个缺点的好方法吗?也许在我忽略的安全投票者中有一种方法可以做到这一点?好的,我和你有同样的问题。对于这个问题,没有简单的方法,您必须使用以下行中的内容覆盖Symfony
Sensio\Bundle\FrameworkExtraBundle\EventListener\SecurityListener的默认SecurityListener
:
use Sensio\Bundle\FrameworkExtraBundle\EventListener\SecurityListener;
class MySecurityListener extends SecurityListener
{
public function onKernelController(FilterControllerEvent $event)
{
$request = $event->getRequest();
if (!$configuration = $request->attributes->get('_acme_security')) {
return;
}
// trick to simulate one security configuration (all in one class/method).
$request->attributes->set('_security', new SecurityConfiguration($configuration));
if (!$this->language->evaluate($configuration->getExpression(), $this->getVariables($request))) {
throw new AccessDeniedException(sprintf($configuration->getMessage());
}
parent::onKernelController($event);
}
}
除此之外,您还需要扩展Sensio\Bundle\FrameworkExtraBundle\Configuration\Security
,如下所示:
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security as SensioSecurity;
/**
* @Annotation
*/
class Security extends SensioSecurity
{
protected $message;
public function getAliasName()
{
return 'acme_security';
}
public function getMessage()
{
return $this->message;
}
}
这将允许您将消息
属性添加到控制器注释中,如果存在AccessDenied异常,将使用该属性
下面介绍如何在Yaml中配置安全侦听器:
acme.security.listener:
class: AppBundle\EventListener\SecurityListener
parent: sensio_framework_extra.security.listener
tags:
- { name: kernel.event_subscriber }
我知道这是一篇老文章,但我也遇到了同样的问题,找到了一个有效的解决方案
PS:我正在使用symfony 3.4.4
其思想是将RequestStack
传递给投票者(构造函数注入),然后获取会话并在flashBag中添加一条消息,然后显示
投票者构造函数:
use Symfony\Component\HttpFoundation\RequestStack;
class ContactVoter extends Voter {
private $requestStack;
function __construct(RequestStack $requestStack) {
$this->requestStack= $requestStack;
}
如果您不使用autowire并希望将其作为参数传递到service.yml中,则可以使用参数:[@request\u stack]
在投票者内部,决定权限的函数:
if ( 'Your_Access_Denied_Condition') {
$this->requestStack->getCurrentRequest()->getSession()->getFlashBag()->add('danger', 'Your message !');
return false ;
}
显示消息的模板
{% if app.request.hasPreviousSession %}
{% for type, messages in app.session.flashbag.all() %}
{% for message in messages %}
<div class="alert alert-{{ type }}">
{{ message|trans({}, 'messages') }}
</div>
{% endfor %}
{% endfor %}
{% endif %}
{%if-app.request.hasPreviousSession%}
{%对于类型,app.session.flashbag.all()中的消息%}
{消息%中的消息为%s}
{{message | trans({},'messages')}
{%endfor%}
{%endfor%}
{%endif%}
如果您不想使用flashBag,您可以使用相同的逻辑抛出带有特定消息的自定义异常,通过侦听器捕获它并显示您想要的消息。这一功能适合您吗?可能是它的一种变体。我可以创建三个独立的投票者,然后修改我的内核控制器事件侦听器来执行这些投票者,这样我就不必在每个操作中都包含代码。