简体   繁体   中英

Symfony2 Security login AdvancedUserInterface bad credentials

I'm struggling trying to make authentication work after having followed the Symfony2 documentation. I always get bad credential on every attempt to login in. I've looked around and found several cases that were due to a short password or salt field length in the database. That is not my case since i'm creating fields with 250 characters length. Here's what i get from logs

doctrine.DEBUG: SELECT i0_.id AS id0, i0_.username AS username1, i0_.email AS email2, i0_.password AS password3, i0_.salt AS salt4, i0_.is_active AS is_active5, i1_.id AS id6, i1_.name AS name7, i1_.role AS role8 FROM iw_users i0_ LEFT JOIN user_userroles u2_ ON i0_.id = u2_.user_id LEFT JOIN iw_user_roles i1_ ON i1_.id = u2_.userroles_id WHERE i0_.username = ? OR i0_.email = ? ["test2","test2"] []

security.yml

security:
encoders:
    Iw\SecurityBundle\Entity\User:
        algorithm:        sha512
        encode_as_base64: true
        iterations:       1
    # Symfony\Component\Security\Core\User\User: plaintext

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

providers:
    administrators:
        entity: { class: IwSecurityBundle:User }

firewalls:
    admin_area:
        pattern:    ^/admin
        http_basic: ~
    secured_area:
        pattern: ^/
        anonymous: ~
        form_login:
            login_path: login
            check_path: login_check
        logout:
            path:   /logout
            target: /

access_control:
    - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/admin, roles: ROLE_ADMIN }

login action

public function loginAction(Request $request)
{
    $session = $request->getSession();

    // get the login error if there is one
    if ($request->attributes->has(SecurityContextInterface::AUTHENTICATION_ERROR)) {
        $error = $request->attributes->get(
            SecurityContextInterface::AUTHENTICATION_ERROR
        );
    } elseif (null !== $session && $session->has(SecurityContextInterface::AUTHENTICATION_ERROR)) {

        $error = $session->get(SecurityContextInterface::AUTHENTICATION_ERROR);
        $session->remove(SecurityContextInterface::AUTHENTICATION_ERROR);
    } else {
        $error = '';
    }

    // last username entered by the user
    $lastUsername = (null === $session) ? '' : $session->get(SecurityContextInterface::LAST_USERNAME);

    return $this->render(
        'IwSecurityBundle:Security:login.html.twig',
        array(
            // last username entered by the user
            'last_username' => $lastUsername,
            'error'         => $error,
        )
    );
}

User entity

class User implements AdvancedUserInterface, \Serializable
{
/**
 * @ORM\Column(type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @ORM\Column(type="string", length=25, unique=true)
 */
private $username;

/**
 * @ORM\Column(type="string", length=60, unique=true)
 */
private $email;

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

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

/**
 * @ORM\Column(name="is_active", type="boolean")
 */
private $isActive;

/**
 * @ORM\ManyToMany(targetEntity="UserRoles", inversedBy="users")
 *
 */
private $roles;

public function __construct()
{
    $this->isActive = true;
    $this->salt = md5(uniqid(null, true));
    $this->roles = new ArrayCollection();
}
}

User repository

public function loadUserByUsername($username)
{
    $q = $this
        ->createQueryBuilder('u')
        ->select('u, r')
        ->leftJoin('u.roles', 'r')
        ->where('u.username = :username OR u.email = :email')
        ->setParameter('username', $username)
        ->setParameter('email', $username)
        ->getQuery();

    try {
        $user = $q->getSingleResult();
    } catch (NoResultException $e) {
        throw new UsernameNotFoundException(sprintf('Unable to find an active admin AcmeUserBundle:User object identified by "%s".', $username), 0, $e);
    }

    return $user;
}

And the form registration service

public function formRegisterAccount($formData, $role = "ROLE_USER") {
    $newUser = new Entity\User;
    $userRoles = $this->em->getRepository('IwSecurityBundle:UserRoles')->findOneBy(array('role' => $role));
    // $encoder = $this -> factory -> getEncoder($newUser);

    if (count($this->getUserByUsernameOrEmail($formData->getUsername(), $formData->getEmail())) > 0) {
        return;
    }

    //Password encoding
    $encoder = $this->factory->getEncoder($newUser);

    $newUser->setUserName($formData->getUsername());
    $newUser->setEmail($formData->getEmail());
    $newUser->setPassword($encoder->encodePassword($formData->getPassword(), $formData->getSalt()));
    // $newUser->setIsActive(FALSE);
    $newUser->addRole($userRoles);

    $this->em->persist($newUser);
    $this->em->flush();
    return $newUser;
}

What am i doing wrong?

Got it solved! I've used the encoderFactory in my service and registration is now working

service.yml

security_service:
    class: Iwooli\SecurityBundle\Service\SecurityService
    arguments: [@security.encoder_factory]

SecurityService

use Symfony\Component\Security\Core\Encoder\EncoderFactory;

class SecurityService {

private $factory;

public function __construct(EncoderFactory $encoderFactory) {
    $this->factory = $encoderFactory;
}

public function formRegisterAccount($formData, $role = "ROLE_USER") {
    $newUser = new Entity\User;

    //Password encoding
    $encoder = $this->factory->getEncoder($newUser);
    $password = $encoder->encodePassword($formData->getPassword(), $newUser->getSalt());
    ...
    $newUser->setPassword($password);
    ...

    return $newUser;
}
}

Hope that helps

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM