0

这一天我一直让自己头疼,

过去几天我一直在学习 Symfony,我的问题很简单,我需要能够使用 3 个参数(用户名、密码和公司)登录

此处提出了相同的问题,但提问者从未提供解决方案: 使用第三个参数的自定义登录

我尝试通过实现令牌、侦听器、提供程序和工厂来克隆 Symfony 的内置登录,但是每当我将密钥插入 security.yml 并尝试登录时,它都会将我带到 /login(找不到“GET /login”的路由")

有人愿意让我开心吗?

编辑:

好的,我又试了一次,现在我有这个错误: Catchable Fatal Error: "Argument 1 passed to Test\SampleBundle\Security\Authentication\Provider\MyProvider::__construct() must be an instance of Symfony\Component\Security\Core \User\UserCheckerInterface,Symfony\Bridge\Doctrine\Security\User\EntityUserProvider 的实例给定”

同样,我要做的就是复制 Symfonys 当前用户/密码登录功能

MyToken.php:

namespace Test\SampleBundle\Security\Authentication\Token;

use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;

class MyToken extends AbstractToken
{
private $credentials;
private $providerKey;


public function __construct($user, $credentials, $providerKey, array $roles = array())
{
    parent::__construct($roles);

    if (empty($providerKey)) {
        throw new \InvalidArgumentException('$providerKey must not be empty.');
    }

    $this->setUser($user);
    $this->credentials = $credentials;
    $this->providerKey = $providerKey;

    parent::setAuthenticated(count($roles) > 0);
}


public function setAuthenticated($isAuthenticated)
{
    if ($isAuthenticated) {
        throw new \LogicException('Cannot set this token to trusted after instantiation.');
    }

    parent::setAuthenticated(false);
}

public function getCredentials()
{
    return $this->credentials;
}

public function getProviderKey()
{
    return $this->providerKey;
}


public function eraseCredentials()
{
    parent::eraseCredentials();

    $this->credentials = null;
}


public function serialize()
{
    return serialize(array($this->credentials, $this->providerKey, parent::serialize()));
}


public function unserialize($serialized)
{
    list($this->credentials, $this->providerKey, $parentStr) = unserialize($serialized);
    parent::unserialize($parentStr);
}
}

MyListener.php:

<?php


namespace Test\SampleBundle\Security\Firewall;

use Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener;
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Psr\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 Test\SampleBundle\Security\Authentication\Token\MyToken;
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;


class MyListener extends AbstractAuthenticationListener
{
private $csrfProvider;


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' . 'b',
        'password_parameter' => '_password',
        'csrf_parameter'     => '_csrf_token',
        'intention'          => 'authenticate',
        'post_only'          => true,
    ), $options), $logger, $dispatcher);

    $this->csrfProvider = $csrfProvider;
}


protected function requiresAuthentication(Request $request)
{
    if ($this->options['post_only'] && !$request->isMethod('POST')) {
        return false;
    }

    return parent::requiresAuthentication($request);
}


protected function attemptAuthentication(Request $request)
{
    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.');
        }
    }

    if ($this->options['post_only']) {
        $username = trim($request->request->get($this->options['username_parameter'], null, true));
        $password = $request->request->get($this->options['password_parameter'], null, true);
    } else {
        $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 MyToken($username, $password, $this->providerKey));
}
}

MyProivder.php:

namespace Test\SampleBundle\Security\Authentication\Provider;


use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
use Symfony\Component\Security\Core\Exception\AuthenticationServiceException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Test\SampleBundle\Security\Authentication\Token\MyToken;
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;


class MyProvider implements AuthenticationProviderInterface
{
private $hideUserNotFoundExceptions;
private $userChecker;
private $providerKey;


    public function __construct(UserCheckerInterface $userChecker, $providerKey, $hideUserNotFoundExceptions = true)
{
    if (empty($providerKey)) {
        throw new \InvalidArgumentException('$providerKey must not be empty.');
    }

    $this->userChecker = $userChecker;
    $this->providerKey = $providerKey;
    $this->hideUserNotFoundExceptions = $hideUserNotFoundExceptions;
}

 public function authenticate(TokenInterface $token)
{
    if (!$this->supports($token)) {
        return null;
    }

    $username = $token->getUsername();
    if (empty($username)) {
        $username = 'NONE_PROVIDED';
    }

    try {
        $user = $this->retrieveUser($username, $token);
    } catch (UsernameNotFoundException $notFound) {
        if ($this->hideUserNotFoundExceptions) {
            throw new BadCredentialsException('Bad credentials', 0, $notFound);
        }
        $notFound->setUsername($username);

        throw $notFound;
    }

    if (!$user instanceof UserInterface) {
        throw new AuthenticationServiceException('retrieveUser() must return a UserInterface.');
    }

    try {
        $this->userChecker->checkPreAuth($user);
        $this->checkAuthentication($user, $token);
        $this->userChecker->checkPostAuth($user);
    } catch (BadCredentialsException $e) {
        if ($this->hideUserNotFoundExceptions) {
            throw new BadCredentialsException('Bad credentials', 0, $e);
        }

        throw $e;
    }

    $authenticatedToken = new MyToken($user, $token->getCredentials(), $this->providerKey, $user->getRoles());
    $authenticatedToken->setAttributes($token->getAttributes());

    return $authenticatedToken;
}


    public function supports(TokenInterface $token)
{
    return $token instanceof MyToken && $this->providerKey === $token->getProviderKey();
}

/**
 * {@inheritdoc}
 */
protected function checkAuthentication(UserInterface $user, MyToken $token)
{
    $currentUser = $token->getUser();
    if ($currentUser instanceof UserInterface) {
        if ($currentUser->getPassword() !== $user->getPassword()) {
            throw new BadCredentialsException('The credentials were changed from another session.');
        }
    } else {
        if ("" === ($presentedPassword = $token->getCredentials())) {
            throw new BadCredentialsException('The presented password cannot be empty.');
        }

        if (!$this->encoderFactory->getEncoder($user)->isPasswordValid($user->getPassword(), $presentedPassword, $user->getSalt())) {
            throw new BadCredentialsException('The presented password is invalid.');
        }
    }
}

/**
 * {@inheritdoc}
 */
protected function retrieveUser($username, MyToken $token)
{
    $user = $token->getUser();
    if ($user instanceof UserInterface) {
        return $user;
    }

    try {
        $user = $this->userProvider->loadUserByUsername($username);

        if (!$user instanceof UserInterface) {
            throw new AuthenticationServiceException('The user provider must return a UserInterface object.');
        }

        return $user;
    } catch (UsernameNotFoundException $notFound) {
        $notFound->setUsername($username);
        throw $notFound;
    } catch (\Exception $repositoryProblem) {
        $ex = new AuthenticationServiceException($repositoryProblem->getMessage(), 0, $repositoryProblem);
        $ex->setToken($token);
        throw $ex;
    }
}
}

我的工厂.php

<?php


namespace Test\SampleBundle\DependencyInjection\Security\Factory;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;

class MyFactory implements SecurityFactoryInterface
{

public function __construct()
{
    $this->addOption('username_parameter', '_username');
    $this->addOption('password_parameter', '_password');
    $this->addOption('csrf_parameter', '_csrf_token');
    $this->addOption('intention', 'authenticate');
    $this->addOption('post_only', true);
}

  public function getPosition()
{
    return 'pre_auth';
}
  public function getKey()
{
    return 'mylogin';
}




public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
    $providerId = 'security.authentication.provider.mylogin.'.$id;
    $container
        ->setDefinition($providerId, new DefinitionDecorator('mylogin.security.authentication.provider'))
        ->replaceArgument(0, new Reference($userProvider))
    ;

    $listenerId = 'security.authentication.listener.mylogin.'.$id;
    $listener = $container->setDefinition($listenerId, new DefinitionDecorator('mylogin.security.authentication.listener'));

    return array($providerId, $listenerId, $defaultEntryPoint);
}

   public function addConfiguration(NodeDefinition $node)
{
}


protected function createEntryPoint($container, $id, $config, $defaultEntryPoint)
{
    $entryPointId = 'security.authentication.form_entry_point.'.$id;
    $container
        ->setDefinition($entryPointId, new DefinitionDecorator('security.authentication.form_entry_point'))
        ->addArgument(new Reference('security.http_utils'))
        ->addArgument($config['login_path'])
        ->addArgument($config['use_forward'])
    ;

    return $entryPointId;
}
    final public function addOption($name, $default = null)
{
    $this->options[$name] = $default;
}
}

服务.yml:

services:

mylogin.security.authentication.provider:
class:  Test\SampleBundle\Security\Authentication\Provider\MyProvider
arguments: ['', %kernel.cache_dir%/security/nonces]

mylogin.security.authentication.listener:
class:  Test\SampleBundle\Security\Firewall\MyListener
arguments: [@security.context, @security.authentication.manager]

最后是注射器:

namespace Test\SampleBundle;

use Test\SampleBundle\DependencyInjection\Security\Factory\MyFactory;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class TestSampleBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
    parent::build($container);

    $extension = $container->getExtension('security');
    $extension->addSecurityListenerFactory(new MyFactory());
}
}

上面的代码中可能有一些错误,因为我一直在玩弄一些东西来让它工作

4

0 回答 0