Silex 检查用户是否在不安全的路由上进行了身份验证

Silex 检查用户是否在不安全的路由上进行了身份验证,silex,symfony-security,Silex,Symfony Security,我正在尝试使用Silex中的symofny/security包构建一个简单的登录,但是我在身份验证检查方面遇到了一个小问题 结构: / /login /admin /login_check /logout 为了进入/admin路由,需要对用户进行身份验证,如果他没有身份验证,他将被重定向到/login表单,然后根据建议,该表单要求管理员/login\u检查进行身份验证(这都是由symofny的安全防火墙提供的) 防火墙配置: 'security.firewalls' =>

我正在尝试使用Silex中的
symofny/security
包构建一个简单的登录,但是我在身份验证检查方面遇到了一个小问题

结构:

/
/login
/admin
    /login_check
    /logout
为了进入
/admin
路由,需要对用户进行身份验证,如果他没有身份验证,他将被重定向到
/login
表单,然后根据建议,该表单要求
管理员/login\u检查
进行身份验证(这都是由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'),
    ));
}
这会引发错误:
令牌存储不包含身份验证令牌。一个可能的原因可能是没有为此URL配置防火墙。
因此,问题是,有没有办法通过本机使用
symfony/security
实现这一点(无需任何漫游)?或者,是否有可能在安全区域内创建
/login
路由,即使用户未登录(例如,对GET请求进行例外),也可以访问该路由,从而解决问题

更新


我还为
/login
页面添加了防火墙配置,其中有一个选项
匿名:true
,这导致不再抛出错误,但是,当我登录到
/admin
路由时,方法
被授予(“角色\管理员”)
会产生
true
,而在
/login
路由上,它会导致
false
(我仍在那里登录)。

您可以通过转储当前令牌轻松了解安全组件的行为

public function index(Request $request, Application $app)
{
    var_dump($application['security.token_storage']->getToken());
}
当您没有为登录页面设置
匿名
选项时(默认为
false
):

当您将登录页面的
匿名
选项设置为
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
下面的示例描述了在初始代码示例中出现错误的原因

如何共享安全令牌? 要在多个防火墙之间共享安全令牌,必须设置相同的安全令牌

SecurityServiceProvider
为使用模式
security.context\u listener.声明的受保护防火墙注册上下文侦听器。
。在您的示例中,它注册为
security.context\u listener.admin
。因此,您要使用的上下文名为
admin

此外,防火墙上下文密钥存储在会话中,因此每个使用它的防火墙必须将其
无状态
选项设置为
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\u checker']->isgrated('ROLE\u ADMIN')
安全地检查权限,并在两个防火墙上获得相同的结果。

您可以通过转储当前令牌轻松了解安全组件的行为

public function index(Request $request, Application $app)
{
    var_dump($application['security.token_storage']->getToken());
}
当您没有为登录页面设置
匿名
选项时(默认为
false
):

当您将登录页面的
匿名
选项设置为
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
下面的示例描述了在初始代码示例中出现错误的原因

如何共享安全令牌? 要在多个防火墙之间共享安全令牌,必须设置相同的安全令牌

SecurityServiceProvider
为使用模式
security.context\u listener.声明的受保护防火墙注册上下文侦听器。
。在您的示例中,它注册为
security.context\u listener.admin
。因此,您要使用的上下文名为
admin

此外,防火墙上下文密钥存储在会话中,因此每个使用它的防火墙必须将其
无状态
选项设置为
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\u checker']->isgrated('ROLE\u ADMIN')
安全地检查权限,并在两个防火墙上获得相同的结果。

您太棒了,谢谢!终于有人找时间解释了。在我再次阅读后,我理解了防火墙部分,但在Silex symfony/security文档中,我没有发现任何关于上下文的内容。没关系,我本可以读到symfony的那本。再次感谢。是的,涉及到这件事的文档很差。我只能建议您在回答问题后立即阅读我为silex文档提供的代码,但它仍在等待批准,我们拭目以待。您太棒了,谢谢!终于有人找时间解释了。在我再次阅读后,我理解了防火墙部分,但在Silex symfony/security文档中,我没有发现任何关于上下文的内容。没关系,我本可以读到symfony的那本。再次感谢。是的,涉及到这件事的文档很差。我只能建议您在回答问题后立即阅读我为silex文档提供的代码