Este foro ya no está activo, así que no puedes publicar nuevas preguntas ni responder a las preguntas existentes.

Problema para acceder con un usuario de BD

6 de abril de 2018

Hola. Tengo una estructura básica de Symfony con dos entidades: User, para los usuarios y Role para los roles. Varios usuarios podrán tener un role (ManyToOne), y un role podrá estar asignado a varios usuarios (OneToMany). Además, tengo dos usuarios creados en configuración. El archivo security.yml incluye:

```security:

Como encoder usamos bcrypt para las contraseñas.

encoders:
    Symfony\Component\Security\Core\User\User:
        algorithm: bcrypt
        cost: 10
    AppBundle\Entity\User:
        algorithm: bcrypt
        cost: 10

Como provider de usuarios definimos en memoria y en base de datos.

providers:
    chain_provider:
        chain:
            providers: [in_memory, user_db]
    in_memory:
        memory:
            users:
                user:
                    password: $2y$10$gMoT8xcqB5OK/zBWyqeSqOrQnAqTz/8yxQrmhVhflvs7qw6r65xpC
                    roles: 'ROLE_USER'
                admin:
                    password: $2y$10$pzphAl3SnvP.UvRmMxKKiuGOoMQghTw7GQ/dZ1s3Kjlm8K0JP73hW
                    roles: 'ROLE_ROOT_ADMIN'
    user_db:
        entity: {class: AppBundle\Entity\User, property: username}```

El AppBundle\Entity\User es así:

```<?php

namespace AppBundle\Entity;

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

/**

  • User */

/**

  • @ORM\Table(name="user")
  • @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository") */

class User implements UserInterface { /**

  • @var int */ private $id;

    /**

  • @var string */ private $firstName;

    /**

  • @var string */ private $familyName;

    /**

  • @var string */ private $username;

    /**

  • @var string */ private $password;

    /**

  • @var string */ private $email;

    /**

  • @var string */ private $language;

    /**

  • @var string */ private $image;

    /**

  • @var string */ private $active;

    /**

  • @var int */ private $role;

    /**

  • Get id.
  • @return int */ public function getId() { return $this->id; }

    /**

  • Set firstName.
  • @param string $firstName
  • @return User */ public function setFirstName($firstName) { $this->firstName = $firstName;

    return $this;

    }

    /**

  • Get firstName.
  • @return string */ public function getFirstName() { return $this->firstName; }

    /**

  • Set familyName.
  • @param string $familyName
  • @return User */ public function setFamilyName($familyName) { $this->familyName = $familyName;

    return $this;

    }

    /**

  • Get familyName.
  • @return string */ public function getFamilyName() { return $this->familyName; }

    /**

  • Set username.
  • @param string $username
  • @return User */ public function setUsername($username) { $this->username = $username;

    return $this;

    }

    /**

  • Get username.
  • @return string */ public function getUsername() { return $this->username; }

    /**

  • Set password.
  • @param string $password
  • @return User */ public function setPassword($password) { $this->password = $password;

    return $this;

    }

    /**

  • Get password.
  • @return string */ public function getPassword() { return $this->password; }

    /**

  • Set email.
  • @param string $email
  • @return User */ public function setEmail($email) { $this->email = $email;

    return $this;

    }

    /**

  • Get email.
  • @return string */ public function getEmail() { return $this->email; }

    /**

  • Set language.
  • @param string $language
  • @return User */ public function setLanguage($language) { $this->language = $language;

    return $this;

    }

    /**

  • Get language.
  • @return string */ public function getLanguage() { return $this->language; }

    /**

  • Set image.
  • @param string $image
  • @return User */ public function setImage($image) { $this->image = $image;

    return $this;

    }

    /**

  • Get image.
  • @return string */ public function getImage() { return $this->image; }

    /**

  • Set active.
  • @param string $active
  • @return User */ public function setActive($active) { $this->active = $active;

    return $this;

    }

    /**

  • Get active.
  • @return string */ public function getActive() { return $this->active; }

    /**

  • Set role.
  • @param int $role
  • @return User */ public function setRole($role) { $this->role = $role;

    return $this;

    }

    /**

  • Get role.
  • @return int */ public function getRole() { return $this->role; }

    public function __construct($role) { $this->setRole($role); }

    public function getRoles() { // TODO: Implement getRoles() method. } public function getSalt() { // TODO: Implement getSalt() method. } public function eraseCredentials() { // TODO: Implement eraseCredentials() method. } }```

El AppBundle/Entity/Role es así: ```<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection; use AppBundle\Entity\User as User;

/**

  • Role */ class Role { /**

    • @var int */ private $id;

    /**

    • @var string */ private $role;

    /**

    • Get id.
    • @return int */ public function getId() { return $this->id; }

    /**

    • Set role.
    • @param string $role
    • @return Role */ public function setRole($role) { $this->role = $role;

      return $this; }

    /**

    • Get role.
    • @return string */ public function getRole() { return $this->role; }

    private $users;

    public function __construct() { $this->users = new ArrayCollection(); }

    public function __toString() { return $this->role; }

    /**

    • Add user.
    • @param \AppBundle\Entity\User $user
    • @return Role */ public function addUser(User $user) { $this->users[] = $user;

      return $this; }

    /**

    • Remove user.
    • @param \AppBundle\Entity\User $user
    • @return boolean TRUE if this collection contained the specified element, FALSE otherwise. */ public function removeUser(User $user) { return $this->users->removeElement($user); }

    /**

    • Get users.
    • @return \Doctrine\Common\Collections\Collection */ public function getUsers() { return $this->users; } }```

Además, tengo las relaciones definidas en yml. El AppBundle/Resources/config/doctrine/User.orm.yml es así:

AppBundle\Entity\User: type: entity table: null repositoryClass: AppBundle\Repository\UserRepository id: id: type: integer id: true generator: strategy: AUTO fields: firstName: type: string length: '100' column: first_name familyName: type: string length: '100' column: family_name username: type: string length: '50' unique: true password: type: string length: '100' email: type: string length: '100' unique: true language: type: string length: '2' image: type: string length: '100' active: type: string length: '1' manyToOne: role: type: integer targetEntity: AppBundle\Entity\Role inversedBy: users joinColumn: name: role referencedColumnName: id lifecycleCallbacks: { }

Y el AppBundle/Resources/config/doctrine/Role.orm.yml es así:

AppBundle\Entity\Role: type: entity table: null repositoryClass: AppBundle\Repository\RoleRepository id: id: type: integer id: true generator: strategy: AUTO fields: role: type: string length: '25' unique: true oneToMany: users: targetEntity: AppBundle\Entity\User mappedBy: role lifecycleCallbacks: { }

El acceso se hace a través de una página con un formulario integrado, así:

```{% extends 'base.html.twig' %} {% block body %} Página principal de la aplicación

{% if error %}
    <div>{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
 
<form action="{{ path('entry_point') }}" method="post">
    <label for="username">Nombre de usuario o correo electrónico:</label>
    <input type="text" id="username" name="username" value="{{ last_username }}" />
 
    <label for="password">Contraseña:</label>
    <input type="password" id="password" name="password" />
 
    <button type="submit">login</button>
</form>

{% endblock %}```

El controlador (adaptado a partir de uno copiado de la docu) es así: ```<?php

namespace AppBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

class DefaultController extends Controller { public function indexAction(Request $request, AuthenticationUtils $authUtils) { // get the login error if there is one $error = $authUtils->getLastAuthenticationError();

// last username entered by the user
    $lastUsername = $authUtils->getLastUsername();
 
    if ($this->getUser() === null) {
        return $this->render('AppBundle::main_app.html.twig', [
            'last_username' => $lastUsername,
            'error'         => $error,
        ]);
    }
 
    $userRol = $this->getUser()->getRoles()[0];
    if ($userRol == 'ROLE_ADMIN' || $userRol == 'ROLE_SUPER_ADMIN' || $userRol == 'ROLE_ROOT_ADMIN') {
        $destination = 'admin_index';
    } elseif ($userRol == 'ROLE_USER') {
        $destination = 'user_index';
    } else {
        return $this->render('AppBundle::main_app.html.twig', [
            'last_username' => $lastUsername,
            'error'         => $error,
        ]);
    }
 
    return $this->redirectToRoute($destination);
}

}```

Cuando accedo con los usuarios que están in_memory no hay problema. Me lo identifica, y me redirecciona correctamente. Sin embargo, si intento acceder con un usuario de la BD, me lanza la siguiente excepción: Type error: Argument 4 passed to Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken::__construct() must be of the type array, null given, called in C:\xampp\htdocs\base_project_dark_q\vendor\symfony\symfony\src\Symfony\Component\Security\Core\Authentication\Provider\UserAuthenticationProvider.php on line 94

Como sólo menciona archivos que son del propio Symfony, que no son los que yo he creado, no sé por donde empezar a mirar. Se supone que debería leer el usuario, leer su rol (por las relaciones entre entidades) y redireccionarme.

¿Alguien sabe lo que estoy haciendo mal? Soy novato en Symfony y cualquier ayuda será agradecida.