Symfony 在身份验证上添加约束
实际上,我在Symfony 在身份验证上添加约束,symfony,authentication,Symfony,Authentication,实际上,我在AuthenticationEvents::AUTHENTICATION\u FAILURE上有一个侦听器,它在Redis缓存中存储failedLogin,如: [ 'ip' => [ 'xxx.xxx.xxx.xxx' => [ 'nbAttempts' => 5, 'lastAttempd' => \DateTime ], ], 'username' => [ 'my_login' =>
AuthenticationEvents::AUTHENTICATION\u FAILURE
上有一个侦听器,它在Redis缓存中存储failedLogin
,如:
[
'ip' => [
'xxx.xxx.xxx.xxx' => [
'nbAttempts' => 5,
'lastAttempd' => \DateTime
],
],
'username' => [
'my_login' => [
'nbAttempts' => 3,
'lastAttempd' => \DateTime
],
'my_other_login' => [
'nbAttempts' => 2,
'lastAttempd' => \DateTime
],
]
]
但是现在,我需要使用这个失败列表来阻止用户在n分钟内尝试连接用户名超过x次时登录,对于IP也是如此(具有其他比率)。(稍后,可能会在块之前添加一个ReCaptcha)
为此,我需要在登录名上添加自定义验证规则。我在文档中找到了它:
checkCredential
非常感谢
编辑(参见结尾处的答案):
我发现了一个高级的guard抽象类:
Symfony\Component\Security\guard\Authenticator\AbstractFormLoginAuthenticator
。然后,身份验证就像在Symfony中一样工作,现在,我只需要在checkCredentials中添加我自己的测试(在getUser()中),我希望在检索用户之前返回错误。您可以侦听事件以查找失败的登录尝试。创建服务:
services:
app.failed_login_listener:
class: AppBundle\EventListener\AuthenticationFailureListener
tags:
- { name: kernel.event_listener, event: security.authentication.failure, method: onAuthenticationFailure }
然后创建侦听器:
<?php
namespace App\EventListener;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
class AuthenticationFailureListener implements AuthenticationFailureHandlerInterface
{
public function onAuthenticationFailure(
Request $request,
AuthenticationException $exception
) {
// do whatever
}
}
<?php
namespace App\EventListener;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class InteractiveLoginListener
{
public function onInteractiveLogin(InteractiveLoginEvent $event)
{
// do whatever
}
}
然后让你的听众:
<?php
namespace App\EventListener;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
class AuthenticationFailureListener implements AuthenticationFailureHandlerInterface
{
public function onAuthenticationFailure(
Request $request,
AuthenticationException $exception
) {
// do whatever
}
}
<?php
namespace App\EventListener;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
class InteractiveLoginListener
{
public function onInteractiveLogin(InteractiveLoginEvent $event)
{
// do whatever
}
}
最后,我通过扩展这个抽象类找到了一个简单的方法:Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator
。这个验证器取代了Symfony使用的默认FormLoginAuthenticator,但非常简单,我们只重写了几个方法
可能只是找到了一种获取config.yml值的方法,以定义路由(避免将其写入此文件,因为我们在config中声明它)
我的服务声明:
app.security.form_login_authenticator:
class: AppBundle\Security\FormLoginAuthenticator
arguments: ["@router", "@security.password_encoder", "@app.login_brute_force"]
我的FormLoginAuthenticator:
<?php
namespace AppBundle\Security;
use AppBundle\Utils\LoginBruteForce;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Router;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
private $router;
private $encoder;
private $loginBruteForce;
public function __construct(Router $router, UserPasswordEncoderInterface $encoder, LoginBruteForce $loginBruteForce)
{
$this->router = $router;
$this->encoder = $encoder;
$this->loginBruteForce = $loginBruteForce;
}
protected function getLoginUrl()
{
return $this->router->generate('login');
}
protected function getDefaultSuccessRedirectUrl()
{
return $this->router->generate('homepage');
}
public function getCredentials(Request $request)
{
if ($request->request->has('_username')) {
return [
'username' => $request->request->get('_username'),
'password' => $request->request->get('_password'),
];
}
return;
}
public function getUser($credentials, UserProviderInterface $userProvider)
{
$username = $credentials['username'];
// Check if the asked username is under bruteforce attack, or if client process to a bruteforce attack
$this->loginBruteForce->isBruteForce($username);
// Catch the UserNotFound execption, to avoid gie informations about users in database
try {
$user = $userProvider->loadUserByUsername($username);
} catch (UsernameNotFoundException $e) {
throw new AuthenticationException('Bad credentials.');
}
return $user;
}
public function checkCredentials($credentials, UserInterface $user)
{
// check credentials - e.g. make sure the password is valid
$passwordValid = $this->encoder->isPasswordValid($user, $credentials['password']);
if (!$passwordValid) {
throw new AuthenticationException('Bad credentials.');
}
return true;
}
}
您可以为该事件编写侦听器。请参见此处:。为安全性。身份验证。失败
事件编写侦听器谢谢,但我已经有了一个存储失败的侦听器,现在我想在登录中添加一个验证签入,其中存储了失败。谢谢,但我已经有一个存储失败的侦听器,现在我想添加一个v验证签入登录,存储失败。更新了我的答案。谢谢,我也编辑了我的帖子,最后我找到了一种方法,通过实现AbstractFormLoginAuthenticator
,轻松完成CustomAuthenticator。很高兴你找到了另一种方法,这似乎是一种很好的方法。我将签出它,并可能在将来使用类似的方法