我试图在Silex中使用X
包构建一个简单的登录,但我在验证检查方面遇到了一个小问题。
结构:
symofny/security
为了进入/
/login
/admin
/login_check
/logout
路由,用户需要进行身份验证,如果不是,则会将其重定向到/admin
表单,然后根据建议将其/login
表示admin/login_check
1}}用于身份验证(这些都是由symofny的安全防火墙提供的)。
防火墙配置:
'security.firewalls' => array(
'login' => array(
'pattern' => '^/login$',
),
'admin' => array(
'pattern' => '^/admin',
'http' => true,
'form' => array(
'login_path' => '/login',
'check_path' => '/admin/login'
),
'logout' => array(
'logout_path' => '/admin/logout',
'invalidate_session' => true
),
'users' => ...
),
)
一切正常,但即使用户已经过身份验证,用户也可以输入/login
路线,这并不是那么糟糕,但我想避免它。我已经厌倦了检查用户身份验证状态,但我想这不起作用,因为我在/login
控制器上检查它,而这不是在"安全"网站的区域。
以下是代码:
public function index(Request $request, Application $app)
{
if ($app['security.authorization_checker']->isGranted('ROLE_ADMIN')) {
return $app->redirect($app['url_generator']->generate('admin'));
}
return $app['twig']->render('login/index.twig', array(
'error' => $app['security.last_error']($request),
'last_username' => $app['session']->get('_security.last_username'),
));
}
引发错误:The token storage contains no authentication token. One possible reason may be that there is no firewall configured for this URL.
所以,问题是,有没有办法在本地使用symfony/security
进行此操作(没有任何转发)?或者在某种程度上可以在安全区域内创建/login
路由,甚至可以访问它 - 尽管用户没有登录(例如,为GET请求做出异常)可以解决问题吗?
更新
我还为/login
页面添加了一个选项anonymous: true
的防火墙配置,导致不再出现错误,但是,当我登录时/admin
路由,方法isGranted('ROLE_ADMIN')
会产生true
,而在/login
路线上,会产生false
(我仍然在那里登录)。
答案 0 :(得分:1)
您可以通过转储当前令牌轻松了解安全组件的行为。
public function index(Request $request, Application $app)
{
var_dump($application['security.token_storage']->getToken());
}
如果没有为登录页面设置anonymous
选项(默认情况下为false
):
null
将登录页面的anonymous
选项设置为true
:
object(Symfony\Component\Security\Core\Authentication\Token\AnonymousToken)
private 'secret' => string 'login' (length=5)
private 'user' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) => string 'anon.' (length=5)
private 'roles' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) =>
array (size=0)
empty
private 'authenticated' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) => boolean true
private 'attributes' (Symfony\Component\Security\Core\Authentication\Token\AbstractToken) =>
array (size=0)
empty
以下示例说明了您在初始代码示例中收到错误的原因。
要在多个防火墙之间共享安全令牌,您必须设置相同的Firewall Context。
SecurityServiceProvider
为使用模式security.context_listener.<name>
声明的 protected 防火墙注册上下文侦听器。在您的示例中,它已注册为security.context_listener.admin
。因此,您要使用的上下文名为admin
。
防火墙上下文密钥也存储在会话中,因此使用它的每个防火墙都必须将其stateless
选项设置为false
。
此外,要在登录页面调用身份验证,anonymous
选项必须设置为true
'security.firewalls' => array(
'login' => array(
'context' => 'admin',
'stateless' => false,
'anonymous' => true,
'pattern' => '^/login$',
),
'admin' => array(
'context' => 'admin',
'stateless' => false,
'pattern' => '^/admin',
'http' => true,
'form' => array(
'login_path' => '/login',
'check_path' => '/admin/login'
),
'logout' => array(
'logout_path' => '/admin/logout',
'invalidate_session' => true
),
'users' => ...
),
)
更改后,如果您登录管理面板和登录页面,您将获得Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken
的实例作为令牌,
如果您尚未登录,请Symfony\Component\Security\Core\Authentication\Token\AnonymousToken
。
因此,您可以使用$app['security.authorization_checker']->isGranted('ROLE_ADMIN')
安全地检查权限,并在两个防火墙上获得相同的结果。