FOSUserBundle有两种身份验证方法

时间:2017-02-15 13:49:01

标签: php symfony fosuserbundle

我有一个Symfony 2.8项目,我正在使用FOSUserBundleFOSUser身份验证方法使用fos_user表来标识和验证凭据以及使用sha512加密的密钥。

是否可以修改或扩展某些类,以便在表fos_user中找不到用户时,在使用md5加密密钥的用户表中查找它?

根据madshvero的日落更新:

我创建了一个用户类:

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

我还创建了用户提供商:

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

并修改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

当然我还修改了services.yml来添加服务app.webservice_user_provider:     服务:         app.form.group:             class:AppBundle \ Form \ GroupFormType             标签:                  - {name:form.type,alias:app_group_registration}

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

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

这样做,行为是系统允许fos_user提供者的用户访问,但不允许我的自定义提供者的用户访问。什么失败了?

这是日志:

[2017-02-16 11:37:08] request.INFO:匹配路由“fos_user_security_check”。 {“route_parameters”:{“_ controller”:“AppBundle \ Controller \ SecurityController :: checkAction”,“_ route”:“fos_user_security_check”},“request_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. [] []

2 个答案:

答案 0 :(得分:0)

您可以通过创建custom provider来检查两个表中的用户,并返回找到的用户。

然后您可以更新app/config/security.yml以使用您的提供商而不是FOSUserBundle提供的提供商:

security:
    providers:
        fos_userbundle:
            id: the.id.of.your.provider

答案 1 :(得分:0)

阅读完文档后,我能够理解身份验证方法的逻辑,并且发现从数据库中为我的项目提供身份验证提供程序更方便,更方便。真的是一个非常简单的解决方案,记录在:How to Load Security Users from the Database (the Entity Provider)

在我使用FOSUserBundle的情况下,有两个注意事项:

  1. 它们必须存在两种身份验证方法:FOSUserBundle提供的方法和MyBundle提供的方法。
  2. 身份验证过程应尝试在两种方法中对用户进行身份验证。
  3. 为此,除了How to Load Security Users from the Database (the Entity Provider)中给出的建议外,您必须修改security.yml的某些部分,使它们看起来像这样::

    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
    

    就是这样。我希望将来有人可以利用这篇文章。非常感谢madshvero的指导。