来自Symfony 2.3安全文档:
如果访问被拒绝,系统将尝试对用户进行身份验证(例如,将用户重定向到登录页面)。如果用户已经登录,将显示403"拒绝访问"错误页面。有关详细信息,请参阅如何自定义错误页。
我目前正在为一些路由使用access_control
规则。如果匿名用户被重定向到登录路径,我想通知他们一条消息,比如"您必须登录才能访问该页面。"我已经阅读了几次安全文档,没有发现任何与此相关的内容。我是不是忽略了什么?
如果没有,当用户被access_control
规则阻止时,如果他们被重定向到登录(即,如果他们只是处于未经授权的角色),最好的通知方式是什么?
编辑:为了澄清,我特别询问如何检查重定向是否是由access_control
规则引起的(如果可能的话,最好是在trick中)。
所以经过大量的研究,我找到了正确的方法。您需要使用入口点服务,并在防火墙配置中定义它。
此方法不会干扰在用于登录的防火墙配置中指定的默认页面设置。
守则
安全性。yml:
firewalls:
main:
entry_point: entry_point.user_login #or whatever you name your service
pattern: ^/
form_login:
# ...
src/Acme/UserBundle/config/services.yml
services:
entry_point.user_login:
class: Acme'UserBundle'Service'LoginEntryPoint
arguments: [ @router ] #I am going to use this for URL generation since I will be redirecting in my service
src/Acme/UserBundle/Service/LoginRetryPoint.php:
namespace Acme'UserBundle'Service;
use Symfony'Component'Security'Http'EntryPoint'AuthenticationEntryPointInterface,
Symfony'Component'Security'Core'Exception'AuthenticationException,
Symfony'Component'HttpFoundation'Request,
Symfony'Component'HttpFoundation'RedirectResponse;
/**
* When the user is not authenticated at all (i.e. when the security context has no token yet),
* the firewall's entry point will be called to start() the authentication process.
*/
class LoginEntryPoint implements AuthenticationEntryPointInterface
{
protected $router;
public function __construct($router)
{
$this->router = $router;
}
/*
* This method receives the current Request object and the exception by which the exception
* listener was triggered.
*
* The method should return a Response object
*/
public function start(Request $request, AuthenticationException $authException = null)
{
$session = $request->getSession();
// I am choosing to set a FlashBag message with my own custom message.
// Alternatively, you could use AuthenticationException's generic message
// by calling $authException->getMessage()
$session->getFlashBag()->add('warning', 'You must be logged in to access that page');
return new RedirectResponse($this->router->generate('login'));
}
}
login.html.trick:
{# bootstrap ready for your convenience ;] #}
{% if app.session.flashbag.has('warning') %}
{% for flashMessage in app.session.flashbag.get('warning') %}
<div class="alert alert-warning">
<button type="button" class="close" data-dismiss="alert">×</button>
{{ flashMessage }}
</div>
{% endfor %}
{% endif %}
资源:
- AuthenticationEntryPointInterface API
- 入口点文档
- 安全配置参考
- 如何自定义表单登录
- 为什么access_denied_handle不起作用-感谢cheesemacfly的提示
我认为kernel.exception
侦听器和设置一个flash消息可以做到这一点。未测试的示例:
use Symfony'Component'HttpKernel'Event'GetResponseForExceptionEvent;
use Symfony'Component'HttpFoundation'Response;
use Symfony'Component'HttpFoundation'Session'SessionInterface;
use Symfony'Component'HttpKernel'Exception'AccessDeniedHttpException;
class My403ExceptionListener
{
protected $session;
public function __construct(SessionInterface $session)
{
$this->session = $session;
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
if ($exception instanceof AccessDeniedHttpException) {
$this->session->getFlashBag()->set('warning', 'You must login to access that page.');
}
}
}
真的不知道它是否有效,或者它是否是正确的。您可以将其注册为kernel.event_listener
。或者,最好编写一个专用服务,并在防火墙配置中将其设置为access_denied_handler
的参数。我认为有很多可能的方法。
难道不能只有两个登录路径吗?
例如,在安全配置中设置
form_login:
login_path: /login_message
在您的登录控制器中
/**
* @Template()
* @Route("/notauthorized", name="login_message")
*/
public function loginMessageAction()
{
return [];
}
然后在您的登录信息.html.twg 中
<a href="{{ path('login') }}">You must login to access this page.</a>
我采用了不同的方法,在控制器中我抛出了新的AuthenticationException
,在此之前,我在flashbag中添加了错误消息。
// Check if user is logged in.
if ($this->isGranted('IS_AUTHENTICATED_REMEMBERED') == FALSE) {
$request->getSession()
->getFlashBag()
->add('error', "Please login to continue");
throw new AuthenticationException();
}
并在登录树枝模板中显示消息。
{% for flash_message in app.session.flashBag.get('error') %}
<div class="callout alert" role="alert">
{{ flash_message }}
</div>
{% endfor %}