将验证码添加到Symfony2登录中 [英] Adding Captcha to Symfony2 Login

查看:58
本文介绍了将验证码添加到Symfony2登录中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要将验证码添加到我的登录页面,我正在使用GregwarCaptchaBundle和FosUserBundle.

I need to add Captcha to my login page, I am using GregwarCaptchaBundle and FosUserBundle.

目前,我使用以下代码在登录名上显示了验证码:

For the moment I have get show the captcha on the login using the following code:

<?php

/*
 * This file is part of the FOSUserBundle package.
 *
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace FOS\UserBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Gregwar\Captcha\CaptchaBuilder;

class SecurityController extends Controller
{
    public function loginAction(Request $request)
    {
        $builtCaptcha = new CaptchaBuilder();
        $builtCaptcha->build();
        $builtCaptcha->save('captcha.jpg');
        /** @var $session \Symfony\Component\HttpFoundation\Session\Session */
        $session = $request->getSession();

        if (class_exists('\Symfony\Component\Security\Core\Security')) {
            $authErrorKey = Security::AUTHENTICATION_ERROR;
            $lastUsernameKey = Security::LAST_USERNAME;
        } else {
            // BC for SF < 2.6
            $authErrorKey = SecurityContextInterface::AUTHENTICATION_ERROR;
            $lastUsernameKey = SecurityContextInterface::LAST_USERNAME;
        }

        // get the error if any (works with forward and redirect -- see below)
        if ($request->attributes->has($authErrorKey)) {
            $error = $request->attributes->get($authErrorKey);
        } elseif (null !== $session && $session->has($authErrorKey)) {
            $error = $session->get($authErrorKey);
            $session->remove($authErrorKey);
        } else {
            $error = null;
        }

        if (!$error instanceof AuthenticationException) {
            $error = null; // The value does not come from the security component.
        }

        // last username entered by the user
        $lastUsername = (null === $session) ? '' : $session->get($lastUsernameKey);

        if ($this->has('security.csrf.token_manager')) {
            $csrfToken = $this->get('security.csrf.token_manager')->getToken('authenticate')->getValue();
        } else {
            // BC for SF < 2.4
            $csrfToken = $this->has('form.csrf_provider')
                ? $this->get('form.csrf_provider')->generateCsrfToken('authenticate')
                : null;
        }
        $t = $request->get('_captcha');
        if($t!=$builtCaptcha){
            echo 'error';
        }
        var_dump($t);

        return $this->renderLogin(array(
            'last_username' => $lastUsername,
            'error' => $error,
            'csrf_token' => $csrfToken,
            'captcha' => $builtCaptcha,
        ));
    }

    /**
     * Renders the login template with the given parameters. Overwrite this function in
     * an extended controller to provide additional data for the login template.
     *
     * @param array $data
     *
     * @return \Symfony\Component\HttpFoundation\Response
     */
    protected function renderLogin(array $data)
    {
        return $this->render('FOSUserBundle:Security:login.html.twig', $data);
    }

    public function checkAction($builtCaptcha)
    {
            return $this->redirect($this->generateUrl('fos_user_login'));
        }
        throw new \RuntimeException('You must configure the check path to be handled by the firewall using form_login in your security firewall configuration.');
    }

    public function logoutAction()
    {
        throw new \RuntimeException('You must activate the logout in your security firewall configuration.');
    }
}

我重写了登录和注册模板,如文档所述(注册验证码工作正常)

And I overrided the login and register template as the documentation explain (the registration is working fine with the captcha)

问题是我不知道如何验证验证码.

The problem is that I don't know how to validate the captcha's code.

我想我应该将其放入checkAction()

I guess that I should do it into the checkAction()

但是我不确定,我对这个问题非常了解.

But I am not sure, I am very caught with this problem.

如果有人能帮助我,我将非常感谢,谢谢.

If someone could help me I would be very grateful, Thanks in advance.

推荐答案

在尝试使用数据库提供程序将Google ReCaptcha实施为简单的登录表单时,我遇到了同样的问题.这是一个基于SecurityEvents :: INTERACTIVE_LOGIN触发的侦听器的可行解决方案.在验证凭据之后但在重定向到security.yml中定义的default_target_path之前,将触发此事件.

I had the same problem when trying to implement Google ReCaptcha into a simple login-form with database provider. This is a working solution based on a listener triggered by SecurityEvents::INTERACTIVE_LOGIN. This event is fired after verification of credentials but before redirecting to default_target_path defined in security.yml.

注意:该示例与其他一些功能混合在一起,因为我还捕获了失败的登录尝试.

Note: The example is mixed with some other functionality, because I am also capturing failed login attempts.

<?php

namespace ExampleBundle\EventListener;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Security\Core\Authentication\Token\AnonymousToken;
use Symfony\Component\Security\Core\AuthenticationEvents;
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
use Symfony\Component\Security\Core\Event\AuthenticationEvent;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use ExampleBundle\Google\GoogleReCaptcha;
use Doctrine\ORM\EntityManager;
use ExampleBundle\Entity\User;

/**
 * Class AuthenticationAttemptListener
 * @package ExampleBundle\EventListener
 */
class AuthenticationAttemptListener implements EventSubscriberInterface
{
    /**
     * @var EntityManager
     */
    private $entityManager;

    /**
     * @var GoogleReCaptcha
     */
    private $googleReCaptcha;

    /**
     * @var integer
     */
    private $maxFailedLoginAttempts;

    /**
     * AuthenticationAttemptListener constructor.
     *
     * @param EntityManager $entityManager
     * @param GoogleReCaptcha $googleReCaptcha
     * @param integer $maxFailedLoginAttempts
     */
    public function __construct(EntityManager $entityManager, GoogleReCaptcha $googleReCaptcha, $maxFailedLoginAttempts)
    {
        $this->entityManager = $entityManager;
        $this->googleReCaptcha = $googleReCaptcha;
        $this->maxFailedLoginAttempts = $maxFailedLoginAttempts;
    }

    /**
     * @return array
     */
    public static function getSubscribedEvents()
    {
        return array(
            AuthenticationEvents::AUTHENTICATION_FAILURE => 'onAuthenticationFailure',
            AuthenticationEvents::AUTHENTICATION_SUCCESS => 'onAuthenticationSuccess',
            SecurityEvents::INTERACTIVE_LOGIN => 'onInteractiveLogin'
        );
    }

    /**
     * Count failed login attempts and save to database on existing usernames
     *
     * @param AuthenticationFailureEvent $event
     */
    public function onAuthenticationFailure(AuthenticationFailureEvent $event)
    {
        if ($event->getAuthenticationException() instanceof BadCredentialsException) {

            $databaseUser = $this->searchUserinDatabase($event);

            // increase failed attempt counter or lock-up account
            if ($databaseUser !== null) {
                if (!$databaseUser->isEnabled()) {
                    throw new CustomUserMessageAuthenticationException('user_deactivated');
                } else {
                    $databaseUser->increaseFailedLoginAttempts();
                    $databaseUser->setFailedLoginLastTimestamp(new \DateTime());
                    if ($databaseUser->getFailedLoginAttempts() == $this->maxFailedLoginAttempts) {
                        $databaseUser->setIsActive(0);
                    }

                    $this->entityManager->persist($databaseUser);
                    $this->entityManager->flush();
                }
            }
        }
    }

    /**
     * @param AuthenticationSuccessEvent $event
     */
    public function onAuthenticationSuccess(AuthenticationEvent $event)
    {
        // Attention: Event will be thrown on every request if you have session-based authentication!
        // Reset of attempt counter may occur if user is logged in while brute force attack is running
    }

    /**
     * Check incoming google recaptcha token and reset attempt-counter on success or throw exception
     *
     * @param InteractiveLoginEvent $event
     */
    public function onInteractiveLogin(InteractiveLoginEvent $event)
    {
        $reCaptchaResponse = $event->getRequest()->get('g-recaptcha-response');
        $captchaRequest = $this->googleReCaptcha->checkReCaptcha($reCaptchaResponse);

        if (is_array($captchaRequest) && $captchaRequest['success'] === true) {
            // reset attempt counter because of successful login and positive recaptcha response
            $databaseUser = $this->searchUserinDatabase($event);

            if ($databaseUser !== null && $databaseUser->isEnabled()) {
                $databaseUser->setFailedLoginAttempts(null);
                $databaseUser->setFailedLoginLastTimestamp(null);

                $this->entityManager->persist($databaseUser);
                $this->entityManager->flush();
            }
        } else {
            // on all other recaptcha related errors throw exception
            throw new CustomUserMessageAuthenticationException('recaptcha_error');
        }
    }

    /**
     * Retrieve user from database
     *
     * @param AuthenticationFailureEvent|AuthenticationEvent $event
     *
     * @return User|null
     */
    private function searchUserinDatabase($event)
    {
        $token = $event->getAuthenticationToken();
        $username = $token->getUsername();
        $databaseUser = null;

        if (!$token instanceof AnonymousToken) {
            // get user from database
            $databaseUser = $this->entityManager->getRepository($entity)->findOneBy(array(
                "username" => $username
            ));
        }

        return $databaseUser;
    }
}

希望有帮助...

这篇关于将验证码添加到Symfony2登录中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆