我是 Symfony2 的新手,但读了很多。首先,我使用的是 symfony 2.1.7。和 FOSUserBundle 用于用户设置。我已经使用用户名和密码覆盖了 fos_user-login 模板。但我想为登录添加验证码。我看过 GregwarCaptchaBundle,根据文档,应该在 FormType 中添加新字段。我的问题来了:symfony 或 FOSUserBundle 登录表单类型在哪里,我可以添加这个新字段,或者覆盖它?存在 ChangePasswordFormType、ProfileFormType...等,但没有 LoginFOrmType。可能很明显,但我没有明白这一点,欢迎任何帮助,请用某种
解决方案编辑问题
看看下面的评论,帕特帮助了我。我创建了一个新的表单类型_username
,_password
并且captcha
字段。当用户名和密码的命名以下划线开始时,'login_check' 路由和 Symfony 身份验证就足够了。然而 Symfony 使用一个监听器来进行登录过程。哪个是UsernamePasswordFormAuthenticationListener
类。虽然我在 Form 类型中添加了验证码字段,但在登录过程中它总是被忽略。(它在页面上呈现,但该字段从未验证,它只是被忽略。)
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('_username', 'email', array('label' => 'form.username', 'translation_domain' => 'FOSUserBundle')) // TODO: user can login with email by inhibit the user to enter username
->add('_password', 'password', array(
'label' => 'form.current_password',
'translation_domain' => 'FOSUserBundle',
'mapped' => false,
'constraints' => new UserPassword()))
->add('captcha', 'captcha');
}
正如我上面提到的UsernamePasswordFormAuthenticationListener
类获取表单输入值,然后重定向你:
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
{
parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
'username_parameter' => '_username',
'password_parameter' => '_password',
'csrf_parameter' => '_csrf_token',
'captcha' => 'captcha',
'intention' => 'authenticate',
'post_only' => true,
), $options), $logger, $dispatcher);
$this->csrfProvider = $csrfProvider;
}
添加了验证码字段。
protected function attemptAuthentication(Request $request)
{
if ($this->options['post_only'] && 'post' !== strtolower($request->getMethod())) {
if (null !== $this->logger) {
$this->logger->debug(sprintf('Authentication method not supported: %s.', $request->getMethod()));
}
return null;
}
if (null !== $this->csrfProvider) {
$csrfToken = $request->get($this->options['csrf_parameter'], null, true);
if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
}
// check here the captcha value
$userCaptcha = $request->get($this->options['captcha'], null, true);
$dummy = $request->getSession()->get('gcb_captcha');
$sessionCaptcha = $dummy['phrase'];
// if captcha is not correct, throw exception
if ($userCaptcha !== $sessionCaptcha) {
throw new BadCredentialsException('Captcha is invalid');
}
$username = trim($request->get($this->options['username_parameter'], null, true));
$password = $request->get($this->options['password_parameter'], null, true);
$request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username);
return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
}
现在,我在登录屏幕上有验证码。我知道,玩 symfony 代码不是一个好方法。如果我找到某种方法来覆盖并调用我自己的函数,我会发布它。
另一个有用的答案
我找到了另一个可能有用的答案 [链接]是否有任何类型的“预登录”事件或类似事件?
按照这个解决方案,我只需覆盖UsernamePasswordFormAuthenticationListener
类并覆盖安全侦听器security.authentication.listener.form.class
参数。代码如下:
namespace TCAT\StaffBundle\Listener;
use Symfony\Component\Security\Http\Firewall\UsernamePasswordFormAuthenticationListener as BaseListener; use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Log\LoggerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface; use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface; use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface; use Symfony\Component\Security\Http\HttpUtils; use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException; use Symfony\Component\Security\Core\SecurityContextInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Security\Core\Exception\BadCredentialsException;
class StaffLoginFormListener extends BaseListener
{
private $csrfProvider;
/**
* {@inheritdoc}
*/
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options
= array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
{
parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
'username_parameter' => '_username',
'password_parameter' => '_password',
'csrf_parameter' => '_csrf_token',
'captcha' => 'captcha',
'intention' => 'authenticate',
'post_only' => true,
), $options), $logger, $dispatcher);
$this->csrfProvider = $csrfProvider;
}
/**
* {@inheritdoc}
*/
protected function attemptAuthentication(Request $request)
{
if ($this->options['post_only'] && 'post' !== strtolower($request->getMethod())) {
if (null !== $this->logger) {
$this->logger->debug(sprintf('Authentication method not supported: %s.', $request->getMethod()));
}
return null;
}
if (null !== $this->csrfProvider) {
$csrfToken = $request->get($this->options['csrf_parameter'], null, true);
if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
throw new InvalidCsrfTokenException('Invalid CSRF token.');
}
}
// throw new BadCredentialsException('Bad credentials');
$userCaptcha = $request->get($this->options['captcha'], null, true);
$dummy = $request->getSession()->get('gcb_captcha');
$sessionCaptcha = $dummy['phrase'];
if ($userCaptcha !== $sessionCaptcha) {
throw new BadCredentialsException('Captcha is invalid');
}
$username = trim($request->get($this->options['username_parameter'], null, true));
$password = $request->get($this->options['password_parameter'], null, true);
$request->getSession()->set(SecurityContextInterface::LAST_USERNAME, $username);
return $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $password, $this->providerKey));
}
}
并将security.authentication.listener.form.class: TCAT\StaffBundle\Listener\StaffLoginFormListener
行添加到 app/config/paramaters.yml 顺便说一句我可以检查我的验证码值。我希望这一切都对你有用。