Mam projekt Symfony 2.8, w którym używam FOSUserBundle. Metoda uwierzytelniania FOSUser używa tabeli fos_user, aby zidentyfikować i zatwierdzić poświadczenia oraz klucz, który jest szyfrowany przy użyciu sha512.

Czy można modyfikować lub rozszerzyć niektóre klasy, aby w przypadku, gdy nie znajdzie użytkownika w tabeli fos_user, szukaj go w tabeli użytkownika, w której klawisz jest szyfrowany przy użyciu md5?

Aktualizacja zgodnie ze startą Madshvero:

Stworzyłem klasę użytkownika:

namespace AppBundle\Security\User;

use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\EquatableInterface;

class WebserviceUser implements UserInterface, EquatableInterface
{
    private $username;
    private $password;
    private $salt;
    private $roles;

    public function __construct($username, $password, $salt, array $roles)
    {
        $this->username = $username;
        $this->password = $password;
        $this->salt = $salt;
        $this->roles = $roles;
    }

    public function getRoles()
    {
        return $this->roles;
    }

    public function getPassword()
    {
        return $this->password;
    }

    public function getSalt()
    {
        return $this->salt;
    }

    public function getUsername()
    {
        return $this->username;
    }

    public function eraseCredentials()
    {
    }

    public function isEqualTo(UserInterface $user)
    {
        if (!$user instanceof WebserviceUser) {
            return false;
        }

        if ($this->password !== $user->getPassword()) {
            return false;
        }

        if ($this->salt !== $user->getSalt()) {
            return false;
        }

        if ($this->username !== $user->getUsername()) {
            return false;
        }

        return true;
    }
}

Utworzyłem również dostawcę użytkownika:

namespace AppBundle\Security\User;

use AppBundle\Security\User\WebserviceUser;
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;

class WebserviceUserProvider implements UserProviderInterface
{
    public function loadUserByUsername($username)
    {
        // make a call to your webservice here
        $userData = true;
        // pretend it returns an array on success, false if there is no user

        if ($userData) {
            $username = 'prueba';
            $password = 'e10adc3949ba59abbe56e057f20f883e'; // md5('123456')
            $salt = '';`enter code here`
            $roles = [ROLE_SUPER_ADMIN];
            // ...

            return new WebserviceUser($username, $password, $salt, $roles);
        }

        throw new UsernameNotFoundException(
            sprintf('Username "%s" does not exist.', $username)
        );
    }

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

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

    public function supportsClass($class)
    {
        return WebserviceUser::class === $class;
    }
}

i zmodyfikuj security.yml:

security:
    access_denied_url:  /login
    encoders:
        FOS\UserBundle\Model\UserInterface: sha512
        AppBundle\Security\User\WebserviceUser: md5

    providers:
        chain_provider:
            chain:
                providers: [fos_userbundle, webservice]

        fos_userbundle:
            id: fos_user.user_provider.username

        webservice:
            id: app.webservice_user_provider

    firewalls:
        main:
            pattern:    ^/
            fr3d_ldap:  ~
            form_login:
                provider:   fos_userbundle
                check_path: /login_check
                login_path: /login
                always_use_default_target_path: true
                default_target_path: /
            logout:
                path: /logout
                target: /login
            anonymous:    true
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        login:
            pattern: ^/login$
            security: false

Oczywiście zmodyfikowałem również usługi.zl, aby dodać aplikację usługową Usługi: app.form.group: Klasa: AppBundle Form GroupFormtype Tagi: - {Name: Form.Type, Alias: app_group_registracja}

    app.form.user:
        class: AppBundle\Form\ProfileFormType
        tags:
            - { name: form.type, alias: app_user_profile }

    app.webservice_user_provider:
        class: AppBundle\Security\User\WebserviceUserProvider

To jest zrobione, zachowaniem jest to, że system umożliwia dostęp dla użytkowników dostawcy Fos_User, ale nie dla użytkowników mojego niestandardowego dostawcy. Co się stanie?

To jest dziennik:

[2017-02-16 11:37:08] Request.info: Dopasowana trasa "Fos_user_Security_Check". {"Route_parametry": {"_ Controller": "Appbundle SecurityController :: CheckAction", "_ trasa": "Fos_user_Security_check"}, "prośba_uri": "http://127.0.0.1:8000/app_dev.php/login_Check"} []

[2017-02-16 11:37:08] doctrine.DEBUG: SELECT t0.id_aspirante AS id_aspirante1, t0.correo AS correo2, t0.clave AS clave3, t0.status_cuenta AS status_cuenta4 FROM aspirantes2 t0 WHERE t0.correo = ? LIMIT 1 ["userFoo"] []

[2017-02-16 11:37:08] doctrine.DEBUG: SELECT t0.id_aspirante AS id_aspirante1, t0.correo AS correo2, t0.clave AS clave3, t0.status_cuenta AS status_cuenta4 FROM aspirantes2 t0 WHERE t0.correo = ? LIMIT 1 ["userFoo"] []

[2017-02-16 11:37:08] security.INFO: Authentication request failed. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AuthenticationServiceException(code: 0): The user provider must return a UserInterface object. at /home/userx/projects/myproj/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php:94, Symfony\\Component\\Security\\Core\\Exception\\AuthenticationServiceException(code: 0): The user provider must return a UserInterface object. at /home/userx/projects/myproj/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php:86)"} []

[2017-02-16 11:37:08] security.DEBUG: Authentication failure, redirect triggered. {"failure_path":"/login"} []

[2017-02-16 11:37:08] request.INFO: Matched route "fos_user_security_login". {"route_parameters":{"_controller":"AppBundle\\Controller\\SecurityController::loginAction","_route":"fos_user_security_login"},"request_uri":"http://127.0.0.1:8000/app_dev.php/login"} []

[2017-02-16 11:37:08] security.INFO: Populated the TokenStorage with an anonymous Token. [] []

[2017-02-16 11:37:08] request.INFO: Matched route "_wdt". {"route_parameters":{"_controller":"web_profiler.controller.profiler:toolbarAction","token":"c368df","_route":"_wdt"},"request_uri":"http://127.0.0.1:8000/app_dev.php/_wdt/c368df"} []

[2017-02-16 11:37:08] security.INFO: Populated the TokenStorage with an anonymous Token. [] []

[2017-02-16 11:37:08] security.DEBUG: Access denied, the user is not fully authenticated; redirecting to authentication entry point. {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException(code: 403): Access Denied. at /home/userx/projects/myproj/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/AccessListener.php:70)"} []

[2017-02-16 11:37:08] security.DEBUG: Calling Authentication entry point. [] []

[2017-02-16 11:37:08] request.INFO: Matched route "fos_user_security_login". {"route_parameters":{"_controller":"AppBundle\\Controller\\SecurityController::loginAction","_route":"fos_user_security_login"},"request_uri":"http://127.0.0.1:8000/app_dev.php/login"} []

[2017-02-16 11:37:08] security.INFO: Populated the TokenStorage with an anonymous Token. [] []
3
Gersón Vizquel 15 luty 2017, 16:49

2 odpowiedzi

Najlepsza odpowiedź

Po przeczytaniu dokumentacji udało mi się zrozumieć logikę metod uwierzytelniania i uznałem go za bardziej wygodne i łatwe w użyciu dla mojego projektu dostawcy uwierzytelniania z bazy danych. Naprawdę jest bardzo proste rozwiązanie, które jest udokumentowane w: Jak załadować użytkowników zabezpieczeń z bazy danych ( dostawca podmiotów)

W moim przypadku za korzystanie z FosuserBunddle są dwa względy:

  1. Muszą istnieć dwie metody uwierzytelniania: ten dostarczony przez fosuserbundle i ten dostarczony przez MyBundle.
  2. Proces uwierzytelniania powinien próbować uwierzytelnić użytkownika w obu metodach.

W tym celu, oprócz zaleceń podanych w Jak załadować użytkowników zabezpieczeń z bazy danych (jednostka Dostawca), musisz modyfikować kilka sekcji Security.yml, aby wyglądały tak ::

encoders:
    // The database method of FOSUserBundle
    FOS\UserBundle\Model\UserInterface:
        algorithm: sha512
    // The data base method of mine
    MyBundle\Entity\MyEntity: 
        //This values depends on how the keys were encrypted in the database
        algorithm: md5
        encode_as_base64: false
        iterations: 0

providers:
    chain_provider:
        chain:
            providers: [fos_userbundle, aspirante_db]

    fos_userbundle:
        id: fos_user.user_provider.username

    myentity_db:
        entity: { class: MyBundle\Entity\MyEntity, property: username }

firewalls:
    main:                                                                                                                              
        pattern:    ^/
        fr3d_ldap:  ~
        form_login:
            provider:   chain_provider //This is the important change
            check_path: /login_check
            login_path: /login
            always_use_default_target_path: true
            default_target_path: /
        logout:
            path: /logout
            target: /login
        anonymous:    true
    dev:
        pattern: ^/(_(profiler|wdt)|css|images|js)/
        security: false
    login:
        pattern: ^/login$
        security: false

To wszystko. Mam nadzieję, że w przyszłości ktoś może skorzystać z tego posta. Wielkie dzięki Madshvero za jego wskazówek.

1
Gersón Vizquel 17 luty 2017, 20:25

Możesz to zrobić, tworząc Dostawca niestandardowy który sprawdza użytkownika w obu stoły i zwraca użytkownik, który znajdzie.

Następnie możesz zaktualizować app/config/security.yml, aby użyć swojego dostawcy zamiast tego dostarczonego przez FosuserBundle:

security:
    providers:
        fos_userbundle:
            id: the.id.of.your.provider
0
madshvero 15 luty 2017, 14:08