首页 文章

symfony2 login_check和自定义身份验证提供程序

提问于
浏览
1

我有来自我的项目的以下代码文件与自定义身份验证提供程序完美相关,我可以在身份验证中拦截请求(TokenInterface $ token),我把echo“it working”;出口;在屏幕上打印消息让我知道它在AuthProvider.php文件中输入了authenticate() .

但是当我尝试将 login_path:/login 更改为 login_path:/user/logincheck_path:/login_checkcheck_path:/user/login_check 并且还修改routing.yml以使UserBundle具有前缀/用户时,问题就会出现,那么代码将会起作用但它不会进入 authenticate() ,但它会打印 "The presented password is invalid" 而不是 "Bad credentials" ,如何将login_check和check_path分别更改为login&login_check以外的其他值,并让我的自定义身份验证提供程序使用新设置?

// app/config/security.yml

security:
    factories:
        - "%kernel.root_dir%/../src/FD/UserBundle/Resources/config/security_factories.yml"

    firewalls:
        checkpoint:
            pattern: ^/
            user: true
            form_login:
                login_path: /login
                check_path: /login_check
            logout:
                path:   /logout
                target: /
            anonymous: ~

    encoders:
        FD\UserBundle\Entity\User: sha512

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    providers:
         user_provider:
             id: user_provider_service

    access_control:
        - { path: ^/_internal, role: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
        - { path: ^/user/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/event/new, roles: ROLE_ADMIN }
        - { path: ^/hello, roles: ROLE_USER }

// app/config/config.yml

imports:
    - { resource: parameters.ini }
    - { resource: security.yml }
    - { resource: @UserBundle/Resources/config/services.yml }

framework:
    #esi:             ~
    translator:      { fallback: %locale% }
    secret:          %secret%
    charset:         UTF-8
    router:          { resource: "%kernel.root_dir%/config/routing.yml" }
    form:            true
    csrf_protection: false
    validation: { enabled: true }
    #validation:      { enable_annotations: true }
    templating:      { engines: ['twig'] } #assets_version: SomeVersionScheme
    session:
        default_locale: %locale%
        auto_start:     true

# Twig Configuration
twig:
    debug:            %kernel.debug%
    strict_variables: %kernel.debug%

# Assetic Configuration
assetic:
    debug:          %kernel.debug%
    use_controller: false
    # java: /usr/bin/java
    filters:
        cssrewrite: ~
        # closure:
        #     jar: %kernel.root_dir%/java/compiler.jar
        # yui_css:
        #     jar: %kernel.root_dir%/java/yuicompressor-2.4.2.jar

# Doctrine Configuration
doctrine:
    dbal:
        default_connection:    default
        connections:
            default:      
                driver:   %database_driver%
                host:     %database_host%
                port:     %database_port%
                dbname:   %database_name%
                user:     %database_user%
                password: %database_password%
                charset:  UTF8
                mapping_types:
                    enum: string
                    set: string
                    blob: object
    orm:
        auto_generate_proxy_classes: %kernel.debug%    
        default_entity_manager:         default # The first defined is used if not set
        entity_managers:
            default:      
                # The name of a DBAL connection (the one marked as default is used if not set)
                connection: ~
                mappings: # Required
                    FDHelloBundle: ~
                    UserBundle: { type: annotation }

      # mappings:
        #   FDHelloBundle: { type: yml, dir: Resources/config/doctrine/metadata/orm }         

# Swiftmailer Configuration
swiftmailer:
    transport: %mailer_transport%
    host:      %mailer_host%
    username:  %mailer_user%
    password:  %mailer_password%

jms_security_extra:
    secure_controllers:  true
    secure_all_services: false

services:
    fd_hello.twig.extension.debug:
        class:        Twig_Extension_Debug
        tags:
             - { name: 'twig.extension' }

    user_provider_service:
        class: FD\UserBundle\Security\User\UserProvider

// app/config/routing.yml

FDHelloBundle:
    resource: "@FDHelloBundle/Resources/config/routing.yml"
    prefix:   /

FDUserBundle:
    resource: "@UserBundle/Controller"
    prefix:   /user
    type: annotation

// src/FD/UserBundle/Controller/LoginController.php

namespace FD\UserBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\Security\Core\SecurityContext;

class LoginController extends Controller
{
    /**
     * @Route("login", name="login")
     */
    public function loginAction()
    {
        $request = $this->getRequest();
        $session = $request->getSession();

        // get the login error if there is one
        $error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
        $session->remove(SecurityContext::AUTHENTICATION_ERROR);

        return $this->render('UserBundle:Login:login.html.twig', array(
            // last username entered by the user
            'last_username' => $session->get(SecurityContext::LAST_USERNAME),
            'error'         => $error,
        ));
    }

    /**
     * @Route("login_check", name="login_check")
     */
    public function loginCheckAction()
    {

    }

    /**
     * @Route("logout", name="logout")
     */
    public function logoutAction()
    {

    }
}

// src/FD/UserBundle/DependencyInjection/Security/Factory/UserFactory.php

namespace FD\UserBundle\DependencyInjection\Security\Factory;

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

class UserFactory implements SecurityFactoryInterface
{
    public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
    {
        $providerId = 'security.authentication.provider.user.'.$id;
        $container
            ->setDefinition($providerId, new DefinitionDecorator('user.security.authentication.provider'))
            ->replaceArgument(0, new Reference($userProvider))
        ;
        $listenerId = 'security.authentication.listener.user.'.$id;
        $listener = $container->setDefinition($listenerId, new DefinitionDecorator('user.security.authentication.listener'));

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

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

    public function getKey()
    {
        return 'user';
    }

    public function addConfiguration(NodeDefinition $node)
    {}
}

// FD/UserBundle/Resources/config/services.yml

services:
    user.security.authentication.provider:
        class:  FD\UserBundle\Security\Authentication\Provider\AuthProvider
        arguments: ['', %kernel.cache_dir%/security/nonces]

    user.security.authentication.listener:
        class:  FD\UserBundle\Security\Firewall\AuthListener

// FD/UserBundle/Resources/config/security_factories.yml

services:
    security.authentication.factory.user:
        class:  FD\UserBundle\DependencyInjection\Security\Factory\UserFactory
        tags:
            - { name: security.listener.factory }

// FD/UserBundle/Security/Authentication/Provider/AuthProvider.php

namespace FD\UserBundle\Security\Authentication\Provider;

use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\NonceExpiredException;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;

use FD\UserBundle\Security\Authentication\Token\UserToken;

class AuthProvider implements AuthenticationProviderInterface
{
    private $userProvider;
    private $cacheDir;

    public function __construct(UserProviderInterface $userProvider, $cacheDir)
    {
        $this->userProvider = $userProvider;
        $this->cacheDir     = $cacheDir;
    }

    public function authenticate(TokenInterface $token)
    {
//        $user = $this->userProvider->loadUserByUsername($token->getUsername());
//        $userToken = new UserToken();
//        $userToken->setUser($user);
echo "it worked"; exit;
        $newToken = new UserToken($token->getUser(), $token->getCredentials(), "user", array("ROLE_ADMIN"));
        $username = $newToken->getUser();
        if (empty($username)) {
            throw new BadCredentialsException('Bad credentials :)');
        }
        return $newToken;

//        if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) {
//            $authenticatedToken = new UserToken($user->getRoles());
//            $authenticatedToken->setUser($user);
//
//            return $authenticatedToken;
//        }
    }

    public function supports(TokenInterface $token)
    {
        return $token instanceof UserToken;
    }
}

// FD/UserBundle/Security/Authenticaion/Token/UserToken.php

namespace FD\UserBundle\Security\Authentication\Token;

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

/**
 * UsernamePasswordToken implements a username and password token.
 *
 */

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

    /**
     * Constructor.
     *
     * @param string $user        The username (like a nickname, email address, etc.)
     * @param string $credentials This usually is the password of the user
     * @param string $providerKey The provider key
     * @param array  $roles       An array of roles
     *
     * @throws \InvalidArgumentException
     */
    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);
    }

    /**
     * {@inheritdoc}
     */
    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;
    }

    /**
     * {@inheritdoc}
     */
    public function eraseCredentials()
    {
        parent::eraseCredentials();

        $this->credentials = null;
    }

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

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

// FD/UserBundle/Security/Firewall/AuthListener.php

namespace FD\UserBundle\Security\Firewall;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Symfony\Component\Security\Http\HttpUtils;


use FD\UserBundle\Security\Authentication\Token\UserToken;

class AuthListener extends AbstractAuthenticationListener
{
    protected $securityContext;
    protected $authenticationManager;
    protected $httpUtils;

    public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager,
                                SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $options = array())
    {
        parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, "user", array_merge(array(
            'username_parameter' => '_username',
            'password_parameter' => '_password',
            'intention' => 'authenticate',
            'post_only' => true,
        ), $options));
    }

    /**
     * Performs authentication.
     *
     * @param  Request $request A Request instance
     *
     * @return TokenInterface The authenticated token, or null if full authentication is not possible
     *
     * @throws AuthenticationException if the authentication fails
     */
    protected function attemptAuthentication(Request $request)
    {

        $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 UserToken($username, $password, $this->providerKey));

    }

    public function getHttpUtils()
    {
        return $this->httpUtils;
    }

    public function setHttpUtils($httpUtils)
    {
        $this->httpUtils = $httpUtils;
    }
}

// src/FD/UserBundle/Security/User/UserProvider.php

namespace FD\UserBundle\Security\User;

use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;

use FD\UserBundle\Entity\User;

class UserProvider implements UserProviderInterface
{
    public function loadUserByUsername($username)
    {
        // make a call to your webservice here
        // $userData = ...
        // pretend it returns an array on success, false if there is no user
        $user = new User();
        $user->setUsername($username);
        $user->setPassword("1234");
        $user->setRoles(array("ROLE_ADMIN"));

        return $user;

//        if ($userData) {
//            // $password = '...';
//            // ...
//
//            return new WebserviceUser($username, $password, $salt, $roles)
//        } else {
//            throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));
//        }
    }

    public function refreshUser(UserInterface $user)
    {
        if (!$user instanceof User) {
            throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
        }

        return $this->loadUserByUsername($user->getUsername());
    }

    public function supportsClass($class)
    {
        return $class === 'FD\UserBundle\Entity\User';
    }
}

1 回答

  • 1

    好像你正在做的一切都是正确的 .

    可能你导入了错误的资源

    FDUserBundle:
        resource: "@UserBundle/Controller"
    

    不应该如下吗?

    FDUserBundle:
        resource: "@FDUserBundle/Controller"
    

相关问题