Symfony2 security: Multiple providers

2019-06-21 03:14发布

问题:

I have 2 bundles in my project:

  • src/Korea/AlmacenBundle
  • src/Galvez/RepuestosBundle

Each with their own database

  • korea_motos -> AlmacenBundle
  • galvez_motos -> RepuestosBundle

Actually my security.yml has only one provider:

providers:
    korea:
        entity: { class: Korea\AlmacenBundle\Entity\Usuario, property: username }

As you can see, both bundles are authenticated by the same table: Usuario, in korea_motos

TABLE: Usuario (korea_motos database)

--ID--|----USERNAME----|---------BUNDLE---

-----1-----|-------------admin----------------|----------AlmacenBundle----------

-----2-----|-------------admin----------------|----------RepuestosBundle-------

Now i want to validate the users, for RepuestosBundle with a table Usuario in galvez_motos, removing the column "bundle" in the previous table.

The problem is in the security.yml file. If i make this:

providers:
    korea:
        entity: { class: Korea\AlmacenBundle\Entity\Usuario, property: username }
    galvez:
        entity: { class: Galvez\RepuestosBundle\Entity\Usuario, property: username }

Symfony launch a exception:

The class 'Galvez\RepuestosBundle\Entity\Usuario' was not found in the chain configured namespaces Korea\AlmacenBundle\Entity

Im trying to use 2 providers, one table per each bundle.. is this possible?

Files: security.yml

jms_security_extra:
secure_all_services: false
expressions: true

security: encoders: Korea\AlmacenBundle\Entity\Usuario: algorithm: sha1 encode_as_base64: false iterations: 1 Galvez\RepuestosBundle\Entity\Usuario: algorithm: sha1 encode_as_base64: false iterations: 1

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

providers:
    korea:
        entity: { class: Korea\AlmacenBundle\Entity\Usuario, property: username }
    galvez:
        entity: { class: Galvez\RepuestosBundle\Entity\Usuario, property: username }

firewalls:
    dev:
        pattern:  ^/(_(profiler|wdt)|css|images|js)/
        security: false

    login:
        pattern:  ^/demo/secured/login$
        security: false

    secured_area:
        pattern:    ^/
        anonymous: ~
        access_denied_handler: accessdenied_handler
        form_login:
            login_path:  /login
            check_path:  /login_check
            default_target_path: /redirect
            always_use_default_target_path: true
        logout:
            path:   /logout
            target: /login
        #anonymous: ~
        #http_basic:
        #    realm: "Secured Demo Area"

access_control:
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/redirect, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/galvez, roles: ROLE_ADMIN_GALVEZ }
    - { path: ^/, roles: ROLE_ADMIN_KOREA }

config.yml -- can't copy/paste all :(

doctrine:
dbal:
    default_connection:   default
    connections:
        default:
            driver:   "%database_driver%"
            dbname:   "%database_name%"
            user:     "%database_user%"
            password: "%database_password%"
            host:     "%database_host%"
            port:     "%database_port%"
            charset:  UTF8
        galvez:
            driver:   %database_driver%
            dbname:   %database_name2%
            user:     %database_user2%
            password: %database_password2%
            host:     %database_host%
            port:     %database_port%
            charset:  UTF8
orm:
    default_entity_manager:   default
    entity_managers:
        default:
            connection:       default
            mappings:
                AlmacenBundle: ~
        galvez:
            connection:       galvez
            mappings:
                RepuestosBundle: ~

parameters.yml

parameters:
database_driver: pdo_mysql
database_host: localhost
database_port: null
database_name: korea_motos
database_user: root
database_password:
mailer_transport: smtp
mailer_host: localhost
mailer_user: null
mailer_password: null
locale: en
secret: 5f7ac4e7c2b38d6dbe55a1f05bee2b02
database_path: null

database_name2: galvez_motos
database_user2: root
database_password2:

PD: Sry for my english :S

回答1:

Old question but for anyone looking for a solution, the manual explains it all here. Basically, you need to chain your providers like this:

# app/config/security.yml
security:
    providers:
        chain_provider:
            chain:
                providers: [korea, galvez]
        korea:
            entity: { class: Korea\AlmacenBundle\Entity\Usuario, property: username }
        galvez:
            entity: { class: Galvez\RepuestosBundle\Entity\Usuario, property: username }


回答2:

This is probably an issue with namespaces of your classes. Check if class Galvez\RepuestosBundle\Entity\Usuario is in the right namespace and if configuration is correct - maybe you accidentally left some copy-and-paste code from the other entity.

Try to persist both of these entities and fetch them (without security context) - I think you'll find your issue there.



回答3:

I made a test with both entities:

abcController.php

$em= $this->get('doctrine')->getManager('galvez');

$usuario_g = $this->get('doctrine')->getRepository('RepuestosBundle:Usuario', 'galvez')->find(1);
$usuario_g->setUsername('asdasd');
$em->persist($usuario_g);
$em->flush();

Works fine, but if i use

$em = $this->getDoctrine()->getEntityManager();

instead of

$em = $this->get('doctrine')->getManager('galvez');

When i try to flush, Symfony launchs the same error:

The class 'Galvez\RepuestosBundle\Entity\Usuario' was not found in the chain configured namespaces Korea\AlmacenBundle\Entity

Usuario.php (AlmacenBundle)

<?php

namespace Korea\AlmacenBundle\Entity;

use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\ORM\Mapping as ORM;

/**
 * Usuario
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Korea\AlmacenBundle\Entity\UsuarioRepository")
 */
class Usuario implements UserInterface
{

/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="username", type="string", length=255)
 */
private $username;

/**
 * @var string
 *
 * @ORM\Column(name="password", type="string", length=255)
 */
private $password;

/**
 * @var string
 *
 * @ORM\Column(name="salt", type="string", length=255)
 */
private $salt;

Usuario.php (RepuestosBundle)

<?php

namespace Galvez\RepuestosBundle\Entity;

use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\ORM\Mapping as ORM;

/**
* Usuario
*
* @ORM\Table()
* @ORM\Entity(repositoryClass="Galvez\RepuestosBundle\Entity\UsuarioRepository")
*/
class Usuario implements UserInterface
{

/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(name="username", type="string", length=255)
 */
private $username;

/**
 * @var string
 *
 * @ORM\Column(name="password", type="string", length=255)
 */
private $password;

/**
 * @var string
 *
 * @ORM\Column(name="salt", type="string", length=255)
 */
private $salt;

PD: Well, i think it's not possible, if i change this:

default_connection: korea

to:

default_connection: galvez

Symfony says:

MappingException: The class 'Korea\AlmacenBundle\Entity\Usuario' was not found in the chain configured namespaces Galvez\RepuestosBundle\Entity

the same error, but in reverse..

It seems like the monolog validation take the default connection (korea in this case) for search and validate