如果用户尝试访问受保护的网址并且不经过身份验证/授权,我需要运行一些代码。
默认情况下,Symfony通过将用户重定向或转发到登录表单来处理未经身份验证的用户。如果请求方法是POST,我想阻止这种情况发生,而是回显JSON对象。
我能想到的最好的方法是创建一个自定义侦听器来侦听kernel.request
事件并检查两件事:
如果是POST请求,并且用户未完全通过身份验证,我会回显JSON对象。
但我的听众(预期)会针对所有请求进行解雇 - 我想将其限制为仅检查请求是否针对受防火墙保护的URL。是否可以以编程方式检查这个?
我也有一种唠叨的怀疑,有一种更简单的方法可以解决这个问题,但无法弄清楚,所以如果有人有任何提示,我很乐意听到它们:)
修改的
@Problematic - 仅检查防火墙请求的原因是因为我有一些没有防火墙的请求,如果我的代码被触发,我将收到上述JSON对象而不是请求的真实响应。
现在,如果我没有登录并向api/get/something
(位于防火墙后面)发出POST请求,Symfony将返回描述登录页面的HTML。相反,我想回应像{error: 'User is not authorized'}
这样的东西。但我只希望在POST请求中发生这种情况。
答案 0 :(得分:3)
我想我是以错误的方式解决这个问题。我想知道一个URL是否在防火墙后面,但我想我应该一直试图找出当前用户是否获得了该请求的授权。在本质上,知道用户被拒绝访问URL意味着URL必须位于防火墙后面,否则访问权限不会被拒绝。
记住这一点,我能够得到我想要的最终结果。一旦你意识到安全机制是如何工作的,这很简单......
Symfony\Component\Security\Http\Firewall
听取了
kernel.request
活动security.yml
AccessDeniedException
,并调度kernel.exception
事件。Symfony/Component/Security/Http/Firewall/ExceptionListener
侦听事件并触发其onKernelException
方法,该方法决定下一步是什么。就我而言,它将启动身份验证过程由于启动身份验证过程是我想要避免的,我编写了自己的事件监听器,在Symfony的kernel.exception
之前拦截ExceptionListener
。我给我的事件监听器优先级为1。
这是我写的方法:
public function handleException(GetResponseForExceptionEvent $event) {
$exception = $event->getException();
$request = $event->getRequest();
if ($request->getMethod() == 'POST') {
if ($exception instanceof AccessDeniedException) {
$response = new Response({err: 'not logged in'});
$event->setResponse($response);
}
}
}
只要用户未获得授权,并且请求方法是POST,就会返回JSON对象(这也会停止事件传播),而不是登录页面的HTML。否则,kernel.exception
的其他听众将做出反应,Symfony可以开展业务。
因此,原始问题仍然没有答案,但我认为可以通过检查用户是否有权访问某个操作来完成。 Symfony\Component\Security\Core\Authorization\AccessDecisionManager
看起来对此有帮助。
修改的
我不知道这个方法仅是否处理未登录的用户。我还没有测试过,但我认为如果(已登录)用户尝试访问需要他们尚未授予角色的行动。如果这会导致问题,我会尝试修改它以使用Symfony\Component\Security\Core\Authentication\AuthenticationTrustResolver
的{{1}}方法来关心未登录的用户。