Symfony3 FosUser 和 FosAuthServer,在 AuthenticationFailureHandler 上使用 LDAP 登录用户

Symfony3 FosUser and FosAuthServer, login user with LDAP on AuthenticationFailureHandler

我在 symfony 中与 FosUser 和 FosAuthServer 一起工作。 我有一个前台网站,可以通过 Oauth2 访问 API。在前台网站上,如果用户未登录,则将他重定向到 oauth 服务器,在用户登录后,将他重定向到带有 oauth2 令牌的字体网站。

它运行良好,但我需要这个: 如果在数据库中找到了用户(我的用户提供者),就 longin 他 如果在数据库中找不到用户,我会在 LDAP 中搜索他并手动登录他。

为此,我使用 AuthenticationFailureHandler 在 LDAP 中查找用户。找到他后,我创建了一个User Entity并发送了enventFOSUserEvents::SECURITY_IMPLICIT_LOGIN,但我不知道我可以创建一个token并重定向到前台网站

security.yml

security:
    encoders:
        AppBundle\Entity\User: sha512
        Symfony\Component\Security\Core\User\User: plaintext

    providers:
        api:
            id: fos_user.user_provider.username_email
        admin:
            memory:
                users:
                    admin:  { password: password}

    firewalls:
        doc:
            pattern:  ^/api/doc
            anonymous: true

        oauth_token:
            pattern:  ^/oauth/v2/token
            security: false

        oauth_authorize:
            pattern:  ^/oauth/v2/auth
            guard:
                authenticators:
                    - app.security.login_form_authenticator
            form_login:
                provider: api
                csrf_token_generator: security.csrf.token_manager
                login_path: fos_user_security_login
                check_path: fos_user_security_check
                failure_handler: app.authentification_failure_handler
            logout:
                path: fos_user_security_logout
                target: fos_user_security_login
            anonymous: true

        admin:
            pattern:  ^/admin
            http_basic:
                realm:    'Secured Area'
                provider: admin
            anonymous:  false

        api:
            pattern:  ^/api
            fos_oauth:  true
            stateless:  true
            anonymous:  false



access_control:
    - { path: ^/oauth/v2/auth, roles: [ IS_AUTHENTICATED_ANONYMOUSLY ] }
    - { path: ^/api/doc, roles: [ IS_AUTHENTICATED_ANONYMOUSLY ] }
    - { path: ^/admin, roles: [ IS_AUTHENTICATED_FULLY ] }
    - { path: ^/, roles: [ ROLE_USER ] }

Service.yml

 app.authentification_failure_handler:
    public: false
    class: AppBundle\Handler\AuthenticationFailureHandler
    arguments:
        - '@utilities.active_directory.ageo'
        - '@doctrine.orm.entity_manager'
        - '@fos_user.user_manager'
        - '@security.token_storage'
        - '@debug.event_dispatcher'
        - '@router'
        - '@http_kernel'
        - '@security.http_utils'

AuthentificationFaillureHandler.php

<?php

namespace AppBundle\Handler;


use AppBundle\Entity\Assure;
use AppBundle\Entity\BrokerStructur;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use FOS\OAuthServerBundle\Model\AuthCodeManager;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Event\UserEvent;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Model\UserManager;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authentication\DefaultAuthenticationFailureHandler;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\HttpUtils;


class AuthenticationFailureHandler extends DefaultAuthenticationFailureHandler
{
   // private $cafeteriaEntityManager;
    private $router;

    /**
     * @var \Ageo\UtilitiesBundle\ActiveDirectory\Ageo      Connection au LDAP Ageo
     */
    private $ldap;

    /**
     * @var $entityManagerSql           Manager des entitées de la base mysql
     */
    private $entityManagerSql;

    /**
     * @var UserManager                 Manager des utilisateurs (FosUserBundle)
     */
    private $userManager;

    /**
     * @var EventDispatcher
     */
    private $eventDispatcher;

    /**
     * @var TokenStorage
     */
    private $tokenStorage;


    public function __construct(\Ageo\UtilitiesBundle\ActiveDirectory\Ageo $ldap, EntityManager $entityManagerSql, UserManager $userManager,
                                TokenStorage $tokenStorage, \Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher  $eventDispatcher,
                                RouterInterface $router, HttpKernelInterface $httpKernel, HttpUtils $httpUtils)
    {
        $this->ldap = $ldap;
        $this->router = $router;
        $this->entityManagerSql = $entityManagerSql;
        $this->userManager = $userManager;
        $this->tokenStorage = $tokenStorage;
        $this->eventDispatcher = $eventDispatcher;
        parent::__construct($httpKernel, $httpUtils, array(), null);

    }

    /**
     * Si l'utilisateur n'est pas présent dans la base de données local, on le cherche dans l'Active directory pour le logguer
     * On vérifie ensuite s'il existe dans la base de donné local. S'il existe, on le charge et on le met à jour, sinon, on le crée.
     * @param Request $request
     * @param AuthenticationException $exception
     * @return RedirectResponse|\Symfony\Component\HttpFoundation\Response
     */
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
    {
        $username = trim($request->request->get('_username'));
        $password = trim($request->request->get('_password'));

        /*
         * Manupulation to find the user in LDAP => $userAd
         */
        $loaclUser = $this->userManager->createUser();
        $loaclUser
            ->setEnabled(true)
            ->setUsername($username)
            ->setPlainPassword($password)
            ->setEmail($userAd->hasAttribute('mail') ? $userAd->getAttribute('mail')[0] : null )

        $this->userManager->updateUser($loaclUser);

        $this->eventDispatcher->dispatch(FOSUserEvents::SECURITY_IMPLICIT_LOGIN, new UserEvent($loaclUser, $request));

        //$this->eventDispatcher->dispatch(FOSUserEvents::REGISTRATION_COMPLETED, new FilterUserResponseEvent($loaclUser, $request, $response));

        // I need to login my user on authServeur


        // I have test this, but it's not working
        if ($this->session->has('_security.oauth_authorize.target_path'))
        {
            parse_str(parse_url($this->session->get('_security.oauth_authorize.target_path'), PHP_URL_QUERY), $target_path);
            $url = $this->session->get('_security.oauth_authorize.target_path');

        }
        $response = new RedirectResponse($url);



        return $response;
    }

}

有人说我可以做与 login_check 相同的过程吗?

我从来没有做过,但这似乎是 chain provider

的用例
security:
    providers:
        chain_provider:
            chain:
                providers: [api, admin, ldap_provider]