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

时间:2017-11-13 22:05:27

标签: silex symfony-security

我试图在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(我仍然在那里登录)。

1 个答案:

答案 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')安全地检查权限,并在两个防火墙上获得相同的结果。