使用约束验证器的Symfony 4简单表单身份验证

时间:2018-07-14 21:47:10

标签: symfony validation security authentication recaptcha

我想在我的自定义登录身份验证中(使用SimpleForm)使用ConstraintValidator来验证此捆绑包的Google Recaptcha EWZRecaptchaBundle我不知道

security.yaml主要防火墙部分:

    providers:
         default:
             entity:
                 class: App:User
                 property: phone
    main:
         pattern: ^/
         anonymous: ~
         provider: default
         simple_form:
               authenticator: App\Security\Authenticator\UserAuthenticator
               check_path: login
               login_path: login
               username_parameter: phone
               password_parameter: password
               use_referer: true
         logout:
               path: logout

我需要在App\Security\Authenticator\UserAuthenticator中使用Validaitor

这是我的自定义身份验证者(App\Security\Authenticator\UserAuthenticator):     

//...

class UserAuthenticator implements SimpleFormAuthenticatorInterface
{
    private $encoder;

    public function __construct(UserPasswordEncoderInterface $encoder)
    {
        $this->encoder = $encoder;
    }

    public function authenticateToken(TokenInterface $token, UserProviderInterface $userProvider, $providerKey)
    {
        try {
            $user = $userProvider->loadUserByUsername($token->getUsername());
        }
        catch (UsernameNotFoundException $exception) {
            throw new CustomUserMessageAuthenticationException("invalid");
        }

        $isPasswordValid = $this->encoder->isPasswordValid($user, $token->getCredentials());
        if ($isPasswordValid) {
            return new UsernamePasswordToken($user, $user->getPassword(), $providerKey, $user->getRoles());
        }

        throw new CustomUserMessageAuthenticationException("invalid");
    }

    public function supportsToken(TokenInterface $token, $providerKey)
    {
        return $token instanceof UsernamePasswordToken && $token->getProviderKey() === $providerKey;
    }

    public function createToken(Request $request, $username, $password, $providerKey)
    {
        return new UsernamePasswordToken($username, $password, $providerKey);
    }
}

1 个答案:

答案 0 :(得分:1)

请查看How to Create a Custom Authentication System with Guard,以更简单,更灵活的方式完成此类自定义身份验证任务。

特别是您将创建的 GuardAuthenticator 类的 getCredentials 方法。

  

getCredentials(请求$ request)       将在每个请求上调用此方法,您的工作是从请求中读取令牌(或任何“身份验证”信息)并返回它。这些凭据随后作为getUser()的第一个参数传递。

或您的任何“身份验证”信息,因此您将能够处理在验证码中传递的值。

<?php

namespace App\Security\Authenticator;


use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\Validator\Validator\Validator\ValidatorInterface;

class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
    /**
     * @var UserPasswordEncoderInterface
     */
    private $encoder;

    /**
     * @var ValidatorInterface
     */
    private $validator;

    /**
     * FormLoginAuthenticator constructor.
     * @param UserPasswordEncoderInterface $encoder
     * @param IsTrueValidator $isTrueValidator
     */
    public function __construct(UserPasswordEncoderInterface $encoder, ValidatorInterface $validator)
    {
        $this->encoder = $encoder;
        $this->validator = $validator;
    }

    /**
     * Return the URL to the login page.
     *
     * @return string
     */
    protected function getLoginUrl()
    {
        return '/login';
    }

    /**
     * Does the authenticator support the given Request?
     *
     * If this returns false, the authenticator will be skipped.
     *
     * @param Request $request
     *
     * @return bool
     */
    public function supports(Request $request)
    {
        return true;
    }

    /**
     *
     * @param Request $request
     *
     * @return mixed Any non-null value
     *
     * @throws \UnexpectedValueException If null is returned
     */
    public function getCredentials(Request $request)
    {
        $violations = $this->validator->validate($request->request->get('g-recaptcha-response'), new IsTrue()); 
        if($violations->count() > 0){ 
            throw new AuthenticationException(self::INVALID_RECAPTCHA); 
        }
        return array(
            'username' => $request->request->get('_username'),
            'password' => $request->request->get('_password'),
        );
    }

    /**
     * Return a UserInterface object based on the credentials.
     *
     * The *credentials* are the return value from getCredentials()
     *
     * You may throw an AuthenticationException if you wish. If you return
     * null, then a UsernameNotFoundException is thrown for you.
     *
     * @param mixed $credentials
     * @param UserProviderInterface $userProvider
     *
     * @throws AuthenticationException
     *
     * @return UserInterface|null
     */
    public function getUser($credentials, UserProviderInterface $userProvider)
    {

        return $userProvider->loadUserByUsername($credentials['username']);
    }

    /**
     * Returns true if the credentials are valid.
     *
     * If any value other than true is returned, authentication will
     * fail. You may also throw an AuthenticationException if you wish
     * to cause authentication to fail.
     *
     * The *credentials* are the return value from getCredentials()
     *
     * @param mixed $credentials
     * @param UserInterface $user
     *
     * @return bool
     *
     * @throws AuthenticationException
     */
    public function checkCredentials($credentials, UserInterface $user)
    {
        $plainPassword = $credentials['password'];

        if (!empty($plainPassword) && !$this->encoder->isPasswordValid($user, $plainPassword)) {
            throw new BadCredentialsException();
        }
        return true;
    }

    /**
     * Called when authentication executed and was successful!
     *
     * If you return null, the current request will continue, and the user
     * will be authenticated. This makes sense, for example, with an API.
     *
     * @param Request $request
     * @param TokenInterface $token
     * @param string $providerKey The provider (i.e. firewall) key
     *
     * @return Response|null
     */
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
    {
        return null;
    }
}

确保您的身份验证者已注册为服务。如果您使用的是default services.yaml配置,则会自动发生。因此,您还可以在GuardAuthenticator的构造函数中传递EWZRecaptchaBundle验证程序,然后可以在发送 getCredentials

中的用户名和密码之前,使用它来验证Recaptcha值。

并像这样更改security.yaml:

providers:
     default:
         entity:
             class: App:User
             property: phone
main:
     pattern: ^/
     anonymous: ~
     provider: default
     guard:
         authenticators:
             - App\Security\FormLoginAuthenticator
     logout: ~