简体   繁体   中英

Symfony2 onAuthenticationSuccess handler and Doctrine2 exception

All! Could someone help me with Symfony2 question? I'd like to save into the database all the events (request related data) regarding user login [success, failure] and logout [success]. Implementation and exception below.

Here is the config.yml

services:

login_success_handler:
    class:  Boomster\LibraryBundle\Handler\LoginSuccessHandler
    arguments:  [@security.context, @doctrine]

login_failure_handler:
    class:  Boomster\LibraryBundle\Handler\LoginFailureHandler
    arguments:  [@security.context, @doctrine]

logout_success_handler:
    class:  Boomster\LibraryBundle\Handler\LogoutSuccessHandler
    arguments:  [@security.context, @doctrine]

Here is firewall security.yml

firewalls:
    secured_area:
        pattern: ^/.*
        form_login:
            check_path: auth_check
            login_path: auth_login
            success_handler: login_success_handler
            failure_handler: login_failure_handler
        logout:
            path:   auth_logout
            target: site_index
            success_handler: logout_success_handler
        anonymous: ~

Here is LoginSuccessHandler handler:

<?php

namespace Boomster\LibraryBundle\Handler;

use Boomster\LibraryBundle\Entity\Visit;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
use Doctrine\Bundle\DoctrineBundle\Registry as Doctrine;

class LoginSuccessHandler implements AuthenticationSuccessHandlerInterface
{
private $doctrine;
private $securityContext;

public function __construct(SecurityContext $securityContext, Doctrine $doctrine)
{
    $this->doctrine = $doctrine;
    $this->securityContext = $securityContext;
}

public function onAuthenticationSuccess(Request $request, TokenInterface $token)
{
    $session = $request->getSession();

    if ($session->has('referer')) {
        if ($session->get('referer') !== null && $session->get('referer') !== '')
        {
            $response = new RedirectResponse($session->get('referer'));
        } else {
            $response = new RedirectResponse($request->getBasePath() . '/');
        }
    } else {
        $response = new RedirectResponse($request->getBasePath() . '/');
    }

    if ($request->isXmlHttpRequest() || $request->request->get('_format') === 'json') {
        $response = new Response(json_encode(array('status' => 'success')));
        $response->headers->set('Content-Type', 'application/json');
    }


    $em = $this->doctrine->getManager();
    $repository = $em->getRepository('BoomsterLibraryBundle:User');
    $user = $repository->findOneByUsername($token->getUsername());

    $visit = new Visit();
    $visit->setFormat($request->request->get('_format', 'none'));
    $visit->setClientIp($request->request->get('client-ip', '0.0.0.0'));
    $visit->setStatus(Visit::SUCCESS);

    // ...
    $user->addVisit($visit);

    $em->persist($visit);
    $em->flush();

    return $response;
}
}

And finally, relations between entities: Entity User

class User .....
/**
 * @var \Doctrine\Common\Collections\Collection
 *
 * @ORM\OneToMany(targetEntity="Visit", mappedBy="user", cascade={"remove"})
 *
 * @var ArrayCollection $visits;
 **/
private $visits;

/**
 * @param Visit $visit
 * @return User $user
 */
public function addVisit($visit)
{
    $this->visits[] = $visit;
    $visit->setUser($this);

    return $this;
}

/**
 * Remove visits
 *
 * @param Visit $visit
 * @return void param \Boomster\LibraryBundle\Entity\Visit $visits
 */
public function removeVisit(Visit $visit)
{
    $this->visits->removeElement($visit);
}

/**
 * @return \Doctrine\Common\Collections\Collection
 */
public function getVisits()
{
    return $this->visits->toArray();
}
}

Entity Visit

class Visit ...
/**
 * @var User $user;
 *
 * @ORM\ManyToOne(targetEntity="User", inversedBy="visits")
 * @ORM\JoinColumn(name="user_id", referencedColumnName="id")
 *
 */
private $user;

// getters & setters for the $user skipped

So, the exception:

An exception occurred while executing 'UPDATE users SET password = ?, salt = ?, updated = ? WHERE id = ?' with params [null, null, "2013-10-18 16:56:48", "141736"]:

SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column "password" violates not-null constraint

As I understand Doctrine trying to update users table, but fields password and salt are null...

Here is the log file:

[2013-10-18 20:47:32] event.DEBUG: Notified event "kernel.request" to listener "Symfony\Component\Security\Http\Firewall::onKernelRequest". [] []
[2013-10-18 20:47:32] doctrine.DEBUG: SELECT t0.id AS id1, t0.nickname AS nickname2, t0.username AS username3, t0.password AS password4, t0.email AS email5, t0.gender AS gender6, t0.website AS website7, t0.skype AS skype8, t0.salt AS salt9, t0.code AS code10, t0.status AS status11, t0.created AS created12, t0.updated AS updated13, t0.expired AS expired14 FROM users t0 WHERE t0.username = ? LIMIT 1 ["admin"] []
[2013-10-18 20:47:32] doctrine.DEBUG: SELECT t0.id AS id1, t0.name AS name2, t0.role AS role3, t0.created AS created4, t0.updated AS updated5 FROM roles t0 INNER JOIN role_user ON t0.id = role_user.role_id WHERE role_user.user_id = ? ["141736"] []
[2013-10-18 20:47:32] security.INFO: User "admin" has been authenticated successfully [] []
[2013-10-18 20:47:32] doctrine.DEBUG: SELECT t0.id AS id1, t0.nickname AS nickname2, t0.username AS username3, t0.password AS password4, t0.email AS email5, t0.gender AS gender6, t0.website AS website7, t0.skype AS skype8, t0.salt AS salt9, t0.code AS code10, t0.status AS status11, t0.created AS created12, t0.updated AS updated13, t0.expired AS expired14 FROM users t0 WHERE t0.username = ? LIMIT 1 ["admin"] []
[2013-10-18 20:47:32] doctrine.DEBUG: SELECT NEXTVAL('seq_visit') [] []
[2013-10-18 20:47:32] doctrine.DEBUG: "START TRANSACTION" [] []
[2013-10-18 20:47:32] doctrine.DEBUG: INSERT INTO visit (id, format, client_ip, status, created, user_id) VALUES (?, ?, ?, ?, ?, ?) {"1":18,"2":"none","3":"0.0.0.0","4":"SUCCESS","5":"2013-10-18 20:47:32","6":"141736"} []
[2013-10-18 20:47:32] doctrine.DEBUG: UPDATE users SET password = ?, salt = ?, updated = ? WHERE id = ? ["NULL","NULL","2013-10-18 20:47:32","141736"] []
[2013-10-18 20:47:32] doctrine.DEBUG: "ROLLBACK" [] []
[2013-10-18 20:47:32] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\Security\Http\Firewall\ExceptionListener::onKernelException". [] []
[2013-10-18 20:47:32] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelException". [] []
[2013-10-18 20:47:32] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\HttpKernel\EventListener\ExceptionListener::onKernelException". [] []
[2013-10-18 20:47:32] request.CRITICAL: Uncaught PHP Exception Doctrine\DBAL\DBALException: "An exception occurred while executing 'UPDATE users SET password = ?, salt = ?, updated = ? WHERE id = ?' with params [null, null, "2013-10-18 20:47:32", "141736"]:

SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "password" violates not-null constraint" at /data/system/webhosts/boomster.lo/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php line 47 {"exception":"[object] (Doctrine\\DBAL\\DBALException: An exception occurred while executing 'UPDATE users SET password = ?, salt = ?, updated = ? WHERE id = ?' with params [null, null, \"2013-10-18 20:47:32\", \"141736\"]:\n\nSQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column \"password\" violates not-null constraint at /data/system/webhosts/boomster.lo/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php:47, PDOException: SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column \"password\" violates not-null constraint at /data/system/webhosts/boomster.lo/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php:784)"} []

The key point:

[2013-10-18 20:47:32] doctrine.DEBUG: UPDATE users SET password = ?, salt = ?, updated = ? WHERE id = ? ["NULL","NULL","2013-10-18 20:47:32","141736"] []

.......... ???

In additional, I've changed $user->addVisit() to $visit->setUser($user). Nothing changed... Here is the detailed log:

[2013-10-18 21:11:33] doctrine.DEBUG: SELECT t0.id AS id1, t0.nickname AS nickname2, t0.username AS username3, t0.password AS password4, t0.email AS email5, t0.gender AS gender6, t0.website AS website7, t0.skype AS skype8, t0.salt AS salt9, t0.code AS code10, t0.status AS status11, t0.created AS created12, t0.updated AS updated13, t0.expired AS expired14 FROM users t0 WHERE t0.username = ? LIMIT 1 ["admin"] []
[2013-10-18 21:11:33] doctrine.DEBUG: SELECT t0.id AS id1, t0.name AS name2, t0.role AS role3, t0.created AS created4, t0.updated AS updated5 FROM roles t0 INNER JOIN role_user ON t0.id = role_user.role_id WHERE role_user.user_id = ? ["141736"] []
[2013-10-18 21:11:33] security.INFO: User "admin" has been authenticated successfully [] []
[2013-10-18 21:11:33] doctrine.DEBUG: SELECT t0.id AS id1, t0.nickname AS nickname2, t0.username AS username3, t0.password AS password4, t0.email AS email5, t0.gender AS gender6, t0.website AS website7, t0.skype AS skype8, t0.salt AS salt9, t0.code AS code10, t0.status AS status11, t0.created AS created12, t0.updated AS updated13, t0.expired AS expired14 FROM users t0 WHERE t0.username = ? LIMIT 1 ["admin"] []
[2013-10-18 21:11:33] doctrine.DEBUG: SELECT NEXTVAL('seq_visit') [] []
[2013-10-18 21:11:33] doctrine.DEBUG: "START TRANSACTION" [] []
[2013-10-18 21:11:33] doctrine.DEBUG: INSERT INTO visit (id, format, client_ip, status, created, user_id) VALUES (?, ?, ?, ?, ?, ?) {"1":19,"2":"none","3":"0.0.0.0","4":"SUCCESS","5":"2013-10-18 21:11:33","6":"141736"} []
[2013-10-18 21:11:33] doctrine.DEBUG: UPDATE users SET password = ?, salt = ?, updated = ? WHERE id = ? ["NULL","NULL","2013-10-18 21:11:33","141736"] []
[2013-10-18 21:11:33] doctrine.DEBUG: "ROLLBACK" [] []
[2013-10-18 21:11:33] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\Security\Http\Firewall\ExceptionListener::onKernelException". [] []
[2013-10-18 21:11:33] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\HttpKernel\EventListener\ProfilerListener::onKernelException". [] []
[2013-10-18 21:11:33] event.DEBUG: Notified event "kernel.exception" to listener "Symfony\Component\HttpKernel\EventListener\ExceptionListener::onKernelException". [] []
[2013-10-18 21:11:33] request.CRITICAL: Uncaught PHP Exception Doctrine\DBAL\DBALException: "An exception occurred while executing 'UPDATE users SET password = ?, salt = ?, updated = ? WHERE id = ?' with params [null, null, "2013-10-18 21:11:33", "141736"]:

SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "password" violates not-null constraint" at /data/system/webhosts/boomster.lo/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php line 47 {"exception":"[object] (Doctrine\\DBAL\\DBALException: An exception occurred while executing 'UPDATE users SET password = ?, salt = ?, updated = ? WHERE id = ?' with params [null, null, \"2013-10-18 21:11:33\", \"141736\"]:\n\nSQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column \"password\" violates not-null constraint at /data/system/webhosts/boomster.lo/vendor/doctrine/dbal/lib/Doctrine/DBAL/DBALException.php:47, PDOException: SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column \"password\" violates not-null constraint at /data/system/webhosts/boomster.lo/vendor/doctrine/dbal/lib/Doctrine/DBAL/Connection.php:784)"} []

Dont understand what is going on... Ideas?

Hello All and thanks a lot to joe42 and Thomas Potaire.

Actually, the key point of this exception located in implementation of UserInterface/AdvancedUserInterface method, described below...

class User implements AdvancedUserInterface .... {
/**
 * Removes sensitive data from the user.
 *
 * This is important if, at any given point, sensitive information like
 * the plain-text password is stored on this object.
 */
public function eraseCredentials()
{
    //$this->salt = $this->password = null;
}

The problem has been solved when I've commented the line of eraseCredentials method... Shit, anyway, why Doctrine2 trying to update user table even in such case:

    $em = $this->doctrine->getManager();
    //$repository = $em->getRepository('BoomsterLibraryBundle:User');
    //$user = $repository->findOneByUsername($token->getUsername());

    $visit = new Visit();
    $visit->setFormat($request->request->get('_format', 'none'));
    $visit->setClientIp($request->request->get('client-ip', '0.0.0.0'));
    $visit->setStatus(Visit::SUCCESS);
    $visit->setUser($token->getUser());

    $em->persist($visit);
    $em->flush();

Again, thanks guys for advance and ideas !!

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