对Symfony登录进行额外的安全检查


Additional security checks on Symfony login

我正在使用symfony 2.5,遇到了一个障碍。

我根据symfony文档使用SecurityContext来验证用户。具体来说,我目前有:

$securityContext = $this->container->get('security.context');
# If authenticated through Symfony
if ($securityContext->isGranted('IS_AUTHENTICATED_FULLY'))
{
    return $this->redirect($this->generateUrl('accounts_dashboard'), 301);
}
.....

这很好用,但这个应用程序从多个位置注册用户,当时我们没有控制重复注册。这意味着同一个电子邮件地址有多个条目。

正因为如此,当有人试图登录,而同一电子邮件地址下有多个帐户时,登录过程会失败,因为它选择了错误的帐户。

我在数据库中还有其他字段可以用来匹配正确的帐户,比如活动状态、上次登录IP甚至上次登录日期。我遇到的问题是,我不确定如何在登录期间创建额外的检查来正确验证该信息。

在不必重新处理整个登录物流的情况下,正确的方法是什么?这样我就可以在调用SecurityContext和登录过程的其余部分之前,对数据库中提供的电子邮件地址进行额外检查?本质上,我只是在提交的登录后尝试进行额外的检查,以确保选择了正确的帐户,而不是数据库中的第一个匹配帐户。

UserProvider应该按用户名返回user,不需要其他任何操作,它不应该做一些繁重的逻辑。我认为您可以尝试通过实现SimpleFormAuthenticatorInterface接口来创建自己的验证器,如本文所述。

您需要实现一个自定义的UserProvider。示例:

<?php
namespace Acme'Security'Authorization;

use Symfony'Bridge'Doctrine'Security'User'EntityUserProvider;
use Symfony'Component'Security'Core'Exception'UsernameNotFoundException;
class MyCustomEmailUserProvider extends EntityUserProvider
{
    /**
     * {@inheritdoc}
     */
    public function loadUserByUsername($username)
    {
        //your code to get user by email goes here
        // if you found User, you need to return it from this method, otherwise throw an exception
        throw new UsernameNotFoundException(sprintf('User "%s" not found.', $username));
    }
}

您不必扩展EntityUserProvider,您可以考虑自己的UserProviderInterface实现。

将其注册为服务(假定为security.my_custom_email_user_provider服务名称),添加所需的依赖项,然后将其添加到security.yml:

providers:
    main:
        id: security.my_custom_email_user_provider

然后在您的登录表单上使用此提供商:

firewalls:
      firewall_name:
            form_login:
                 provider: main

查看Cookbook文章了解更多信息。