Symfony登录表单添加其他字段

时间:2018-10-10 22:13:24

标签: symfony

我的应用程序上有多个防火墙,对于其中一个,我需要在symfony登录表单上再添加一个字段。

除了usernamepassword之外,我还需要恢复用户必须填写的字段"code"才能登录此防火墙。

我在官方symfony文档中看到了这一点:

https://symfony.com/doc/current/security/custom_password_authenticator.html

但是我不知道如何处理表单中的新字段。

我不使用fosuserbundle,也不需要使用它。

这是为认证系统创建自定义表单登录名的symfony建议

// src/Security/TimeAuthenticator.php
namespace App\Security;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Http\Authentication\SimpleFormAuthenticatorInterface;

class TimeAuthenticator 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) {
            // CAUTION: this message will be returned to the client
            // (so don't put any un-trusted messages / error strings here)
            throw new CustomUserMessageAuthenticationException('Invalid username or password');
        }

        $currentUser = $token->getUser();

        if ($currentUser instanceof UserInterface) {
            if ($currentUser->getPassword() !== $user->getPassword()) {
                throw new BadCredentialsException('The credentials were changed from another session.');
            }
        } else {
            if ('' === ($givenPassword = $token->getCredentials())) {
                throw new BadCredentialsException('The given password cannot be empty.');
            }
            if (!$this->encoder->isPasswordValid($user, $givenPassword)) {
                throw new BadCredentialsException('The given password is invalid.');
            }
        }

        $currentHour = date('G');
        if ($currentHour < 14 || $currentHour > 16) {
            // CAUTION: this message will be returned to the client
            // (so don't put any un-trusted messages / error strings here)
            throw new CustomUserMessageAuthenticationException(
                'You can only log in between 2 and 4!',
                array(), // Message Data
                412 // HTTP 412 Precondition Failed
            );
        }

        return new UsernamePasswordToken(
            $user,
            $user->getPassword(),
            $providerKey,
            $user->getRoles()
        );
    }

    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);
    }
}

在此示例中,没有多余的字段恢复。

这是symfony身份验证的默认表单登录名,我目前正在使用它:

<form action="{{ path('login') }}" method="post">
    <label for="username">Username:</label>
    <input type="text" id="username" name="_username" value="{{ last_username }}" />

    <label for="password">Password:</label>
    <input type="password" id="password" name="_password" />

    {#
        If you want to control the URL the user
        is redirected to on success (more details below)
        <input type="hidden" name="_target_path" value="/account" />
    #}

    <button type="submit">login</button>
</form>

我想在此表单中添加一个字段,并在我的自定义SimpleFormAuthenticatorInterface中恢复它以执行身份验证逻辑,我需要这个额外的字段。

预先感谢您的建议。

1 个答案:

答案 0 :(得分:1)

要将其他请求参数获取到类中,可以将RequestStack注入到TimeAuthenticator中:

class TimeAuthenticator implements SimpleFormAuthenticatorInterface
{
    private $encoder;

    private $requestStack;

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

    public function getOneTimeToken() : ?string
    {
        $this->requestStack->getCurrentRequest()->request->get('yourNewField', null);
    }
    //...

然后使用新方法通过authenticateToken()方法针对用户检查提交的值。

还请检查GuardAuthenticator系统,因为它更适合您的需求。