Symfony 3 bcrypt password does not verify

被刻印的时光 ゝ 提交于 2019-12-10 23:35:43

问题


Most likely I am missing some silly stuff, but I spent quite some time on this, so any help is appreciated.

The authentication is based upon this tutorial

I am using bcrypt to encode the password and it seems that is working properly on user signup.

But when logging in it throws error below, even though the password entered is correct:

Invalid credentials.

I verified that the email and password arrive properly at the login authenticator ( login form is submitted via Ajax ).

Also the getUser() method seems to be doing its job of retrieving $user object and the corresponding password from the db.

The security.yml is set as follows:

security:
encoders:
    UsedBundle\Entity\User: 
        algorithm: bcrypt

This is the registration controller:

namespace UsedBundle\Controller;

use UsedBundle\Form\UserType;
use UsedBundle\Entity\User;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use UsedBundle\Service\sendEmail;

class RegistrationController extends Controller
{
/**
 * @Route("/inscription", name="inscription")
 */
public function registerAction(Request $request)
{
    $user = new User();
    $form = $this->createForm(UserType::class, $user);

    if ($request->isMethod('POST')) {
       $form->submit($request->request->get($form->getName('user')));
        if(!$form->isValid()){ 
           // handle invalid form 
        }
        if ($form->isSubmitted() && $form->isValid()) {
            $password = $this->get('security.password_encoder')
                ->encodePassword($user, $user->getPlainPassword());
            $user->setPassword($password);
            $user->setUserKey( $user->getEmail() );
            $user->setUserKeyTime();
            $user->setDateReg();

            $em = $this->getDoctrine()->getManager('used');
            $em->persist($user);
            $em->flush();

            return new JsonResponse(array(
                'status' => 'ok',
                'message' => 'Success!')
            );
        }
    }else{
        return $this->render(
            'common/register.html.twig',
            array('form' => $form->createView())
        );           
    }
}
}

The login form authenticator ( setup as a service ):

namespace UsedBundle\Security;

use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Security;
use UsedBundle\Entity\User;
use UsedBundle\Repository\UserRepository;
use Symfony\Component\Security\Core\Exception\BadCredentialsException;

class FormLoginAuthenticator extends AbstractFormLoginAuthenticator
{
private $container;

public function __construct(ContainerInterface $container)
{
    $this->container = $container;
}

public function getCredentials(Request $request)
{
    if ($request->getPathInfo() != '/login_check') {
        return;
    }
    $username = $request->request->get('_email');
    $request->getSession()->set(Security::LAST_USERNAME, $username);
    $password = $request->request->get('_password');
    return array(
        'username' => $username,
        'password' => $password
    );
}

public function getUser($credentials, UserProviderInterface $userProvider)
{
    $username = $credentials['username'];
    $user = $this->container
         ->get('doctrine')
         ->getRepository('UsedBundle:User', 'used')
         ->findOneByemail( $username );
    return $user;
}

public function checkCredentials($credentials, UserInterface $user)
{
    $plainPassword = $credentials['password'];
    $encoder = $this->container->get('security.password_encoder');

    if (!$encoder->isPasswordValid($user, $plainPassword)){
        throw new BadCredentialsException();
    }else{
        $this->pass_error = 'no error';
    }
}

protected function getLoginUrl()
{
    return $this->container->get('router')
        ->generate('homepage');
}

protected function getDefaultSuccessRedirectUrl()
{
    return $this->container->get('router')
        ->generate('homepage');
}


public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
    // AJAX! Return some JSON
    if ($request->isXmlHttpRequest()) {
        return new JsonResponse(
            array('userId' => $token->getUser()->getId(),
                'statut' => 'ok'
                )
        );
    }
    // for non-AJAX requests, return the normal redirect
    return parent::onAuthenticationSuccess($request, $token, $providerKey);
}

public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
    return new JsonResponse(
        array('message' => $exception->getMessageKey(),
            'statut' => 'error',
            'passerror' => $this->pass_error )

    );
}

Excerpt of var_dump($user) on checkCredentials() as requested

object(UsedBundle\Entity\User)#329 (15) {
["id":"UsedBundle\Entity\User":private]=>
int(7)
["avatar":"UsedBundle\Entity\User":private]=>
string(11) "dsfdfafadfa"
["name":"UsedBundle\Entity\User":private]=>
string(9) "dfdffadfa"
["password":"UsedBundle\Entity\User":private]=>
string(64)   "jjuewij/sc9Af17i+ZXAUcrdiZX83HHMLjTNVSnJ34qGCp6BAxisVtjiG3Nm+uH5"
["plainPassword":"UsedBundle\Entity\User":private]=>
NULL
["email":"UsedBundle\Entity\User":private]=>
string(22) "myemail@gmail.com"
["phone":"UsedBundle\Entity\User":private]=>
string(12) "445454545454"
["roles":"UsedBundle\Entity\User":private]=>
string(9) "ROLE_USER"
["isActive":"UsedBundle\Entity\User":private]=>
bool(true)

as requested, excerpts of var_dump($exception) on onAuthenticationFailure()

object(Symfony\Component\Security\Core\Exception\BadCredentialsException)#322 (8) {
["token":"Symfony\Component\Security\Core\Exception\AuthenticationException":private]=>
object(Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken)#61 (6) {
["credentials":"Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken":private]=>
array(2) {
  ["username"]=>
  string(22) "myemail@gmail.com"
  ["password"]=>
  string(8) "senha444"
}
["guardProviderKey":"Symfony\Component\Security\Guard\Token\PreAuthenticationGuardToken":private]=>
string(6) "main_0"
["user":"Symfony\Component\Security\Core\Authentication\Token\AbstractToken":private]=>
NULL
["roles":"Symfony\Component\Security\Core\Authentication\Token\AbstractToken":private]=>
array(0) {
}
["authenticated":"Symfony\Component\Security\Core\Authentication\Token\AbstractToken":private]=>
bool(false)
["attributes":"Symfony\Component\Security\Core\Authentication\Token\AbstractToken":private]=>
array(0) {
}
}
["message":protected]=>
string(0) ""
["string":"Exception":private]=>
string(0) ""
["code":protected]=>
int(0)
["file":protected]=>
string(78) "/Users/BAMAC/Sites/Symfony1/src/UsedBundle/Security  /FormLoginAuthenticator.php"
["line":protected]=>
int(58)

回答1:


After Edwin put me in the right direction, I managed to get this to work. In reality the encryption was not the only issue. The changes concern mainly the registration controller, where the code for password encryption was modified. I also changed the form authenticator which is now based upon this

as the previous base indicated on my question is outdated.

Finally, Symfony are not very much friends with Ajax, so the Ajax URL was adapted to work for dev environment.

Here is the whole code:

security.yml

security:
encoders:
    UsedBundle\Entity\User: 
        algorithm: bcrypt
providers:
    db_provider:
        entity:
            class: UsedBundle:User
            property: email
            manager_name: used

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

    main:
        anonymous: ~
        provider: db_provider
        form_login: 
            login_path: /
            username_parameter: _email
            check_path: /login_check
        guard:
            authenticators:
                - app.form_login_authenticator 
        logout:
            path:   /logout
            target: /
access_control:
    - { path: ^/admin, roles: ROLE_ADMIN }
    - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY }

Changes on registration controller:

 if ($form->isSubmitted() && $form->isValid()) {
     $this->formData = $request->request->get($form->getName('user'));
     $this->plainPassword = $this->formData['plainPassword']['first'];
     $password = $this->get('security.password_encoder')
                ->encodePassword($user, $this->plainPassword );
  .....

The new authenticator:

namespace UsedBundle\Security;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Guard\AbstractGuardAuthenticator;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Core\Security;


class FormLoginAuthenticator extends AbstractGuardAuthenticator
{
private $container;

public function __construct(ContainerInterface $container)
{
    $this->container = $container;
}

public function getCredentials(Request $request)
{
    if ($request->getPathInfo() != '/login_check') {
        return;
    }
    $email = $request->request->get('_email');
    $request->getSession()->set(Security::LAST_USERNAME, $email);
    $password = $request->request->get('_password');
    return array(
        'email' => $email,
        'password' => $password
    );
}

public function getUser($credentials, UserProviderInterface $userProvider)
{
    $email = $credentials['email'];
    return $this->user = $this->container
         ->get('doctrine')
         ->getRepository('UsedBundle:User', 'used')
         ->findOneByemail( $email );
}

public function checkCredentials($credentials, UserInterface $user)
{
    $plainPassword = $credentials['password'];
    $encoder = $this->container->get('security.password_encoder');
    if (!$encoder->isPasswordValid($user, $plainPassword)){
        throw new BadCredentialsException();
    }else{
        return true;
    }
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
{
    $session=$request->getSession();
    $session->set('seller_id', $token->getUser()->getId());
    $session->set('email', $token->getUser()->getEmail());
    return new JsonResponse(
        array(
            'userId' => $token->getUser()->getId(),
            'message' => $this->credentials,
            'statut' => 'ok',
            'roles' => $token->getUser()->getRoles(),
            'email' => $token->getUser()->getEmail(),
            )
    );

    // for non-AJAX requests, return the normal redirect
    //return parent::onAuthenticationSuccess($request, $token, $providerKey);
}

public function onAuthenticationFailure(Request $request, AuthenticationException $exception)
{
    $data = array(
        'message' => strtr($exception->getMessageKey(), $exception->getMessageData())

        // or to translate this message
        // $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
    );

    return new JsonResponse($data, Response::HTTP_FORBIDDEN);
}

/**
 * Called when authentication is needed, but it's not sent
 */
public function start(Request $request, AuthenticationException $authException = null)
{

    $data = array(
        'message' => 'Authentication Required'
    );

    return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);

}

public function supportsRememberMe()
{
    return false;
}

}

The login controller:

namespace UsedBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;

class LoginController extends Controller
{
/**
 * @Route("/login", name="login")
 */
public function loginAction(Request $request)
{
    $helper = $this->get('security.authentication_utils');
    return $this->render('common/login.html.twig', array(
        // last username entered by the user (if any)
        'last_username' => $helper->getLastUsername(),
        // last authentication error (if any)
        'error' => $helper->getLastAuthenticationError(),
    ));

}

/**
 * @Route("/login_check", name="security_login_check")
 */
public function loginCheckAction()
{
    // will never be executed
}
}

And this is how the Ajax url should look like while in dev:]

            $.ajax({
            url: "/app_dev.php/login_check",
            type: "POST",
            dataType: "json",
            data: str,
            success: function(data) {
    .....


来源:https://stackoverflow.com/questions/44921412/symfony-3-bcrypt-password-does-not-verify

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!