PdoSessionHandler FOSUserBundle登录

PdoSessionHandler FOSUserBundle登录,session,symfony,doctrine-orm,Session,Symfony,Doctrine Orm,我已实现将会话保存到数据库中,但问题是,在我将其应用到我的应用程序后,登录不起作用,它似乎没有根据以下日志获取实体: [2014-02-26 05:47:10]request.INFO:匹配的路由“fos\u用户安全检查”(参数:“\u控制器”:“fos\UserBundle\controller\SecurityController::checkAction”,“\u路由”:“fos\u用户安全检查”[] [2014-02-26 05:47:10]event.DEBUG:通知侦听器“Symfo

我已实现将会话保存到数据库中,但问题是,在我将其应用到我的应用程序后,登录不起作用,它似乎没有根据以下日志获取实体:

[2014-02-26 05:47:10]request.INFO:匹配的路由“fos\u用户安全检查”(参数:“\u控制器”:“fos\UserBundle\controller\SecurityController::checkAction”,“\u路由”:“fos\u用户安全检查”[]

[2014-02-26 05:47:10]event.DEBUG:通知侦听器“Symfony\Component\HttpKernel\EventListener\LocaleListener::onKernelRequest”的事件“kernel.request”。[][]

[2014-02-26 05:47:10]event.DEBUG:向侦听器“Symfony\Component\Security\Http\Firewall::onKernelRequest”通知事件“kernel.request”。[][]

[2014-02-26 05:47:10]security.INFO:身份验证请求失败:CSRF令牌无效。[][]

[2014-02-26 05:47:10]security.DEBUG:重定向到/登录[]

与默认的sessionhandler不同,默认的sessionhandler可以正常登录:

[2014-02-26 07:10:07]request.INFO:匹配的路由“fos_用户安全检查”(参数:“_控制器”:“fos\UserBundle\controller\SecurityController::checkAction”,“_路由”:“fos_用户安全检查”[]

[2014-02-26 07:10:07]event.DEBUG:通知侦听器“Symfony\Component\HttpKernel\EventListener\LocaleListener::onKernelRequest”的事件“kernel.request”。[][]

[2014-02-26 07:10:07]event.DEBUG:向侦听器“Symfony\Component\Security\Http\Firewall::onKernelRequest”通知事件“kernel.request”。[][]

[2014-02-26 07:10:07]条令调试:选择t0.username作为用户名1,t0.username\u canonical作为用户名\u canonical 2,t0.email作为电子邮件3,t0.email\u canonical作为电子邮件\u canonical 4,t0.enabled作为启用,t0.salt作为密码,t0.last作为最后登录,t0.locked作为锁定,t0.expired作为过期,t0.expires_at AS expires_at 11,t0.confirmation_to AS confirmation_token 12,t0.password_at AS password_required_at 13,t0.roles AS roles 14,t0.credentials_过期为credentials_expired_at AS credentials_过期为credentials_at 16,t0.id为id17,t0.first_name为first_name为first_name 18,t0.last_为last_name为last_19,t0.date_创建为date_从用户t0创建20,其中t0.username_canonical=?限制1[“rainercedric23”][]

[2014-02-26 07:10:07]security.INFO:用户“rainercedric23”已成功通过身份验证[]

如您所见,日志显示,与默认会话处理程序相比,PdoSessionHandler与条令没有交互。我还注意到,在提交表单之后,侦听器无法获取导致身份验证请求失败的CSRF令牌

更新:

这是不带CSRF令牌的日志,它对用户进行身份验证,但在用户离开页面后,它会在数据库中写入另一个会话,从而使下一个页面用户令牌再次匿名:

[2014-02-26 07:39:59]security.INFO:用户“rainercedric23”已成功通过身份验证[]

[2014-02-26 07:39:59]security.DEBUG:从会话中读取SecurityContext[]

[2014-02-26 07:39:59]security.DEBUG:从用户提供程序重新加载用户。[][]

[2014-02-26 07:39:59]条令调试:选择t0.username作为用户名1,t0.username作为用户名2,t0.email作为电子邮件3,t0.email作为电子邮件4,t0.enabled作为启用,t0.salt作为密码7,t0.last作为最后登录,t0.locked作为锁定,t0.expired作为过期,t0.expires_at AS expires_at 11,t0.confirmation_to AS confirmation_token 12,t0.password_at AS password_required_at 13,t0.roles AS roles 14,t0.credentials_过期为credentials_expired_at AS credentials_过期为credentials_at 16,t0.id为id17,t0.first_name为first_name为first_name 18,t0.last_为last_name为last_19,t0.date_创建为date_从用户t0创建20,其中t0.id=?限制1[7][]

[2014-02-26 07:39:59]security.DEBUG:已从用户提供程序重新加载用户名“rainercedric23”。[][]

[2014-02-26 07:40:00]security.DEBUG:在会话中写入SecurityContext[]

[2014-02-26 07:40:00]security.INFO:使用匿名令牌填充SecurityContext[]

[2014-02-26 07:40:00]security.DEBUG:访问被拒绝(用户未通过完全身份验证)

[2014-02-26 07:40:00]security.DEBUG:调用身份验证入口点[][]


有没有办法解决这个问题?谢谢~

多亏了Daniel15,我在包中创建了一个customPdoSessionHandler,找到了一个解决方案(我调整了一些代码,以便能够在Symfony2中使用它),我将PdoSessionHandler作为customPdoSessionHandler的basehandler

<?php

namespace foo\barBundle\Handler;

use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler as baseHandler;

/**
 * PDO Session Handler
 * @author Daniel15 <dan.cx>
 *
 * This class is actually static, but since PHP doesn't support static classes, abstract is close
 * enough. You do not instantiate the class; you just call the static "init" method.
 */
class CustomPdoSessionHandler extends baseHandler {

    private static $db;
private static $oldData;
private $pdo;
private $dbOptions;

public function __construct(\PDO $pdo, array $dbOptions = array())
{

    if (!array_key_exists('db_table', $dbOptions)) {
        throw new \InvalidArgumentException('You must provide the "db_table" option for a PdoSessionStorage.');
    }
    if (\PDO::ERRMODE_EXCEPTION !== $pdo->getAttribute(\PDO::ATTR_ERRMODE)) {
        throw new \InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION))', __CLASS__));
    }

    $this->pdo = $pdo;
    $this->dbOptions = array_merge(array(
        'db_id_col'   => 'session_id',
        'db_data_col' => 'data',
        'db_time_col' => 'last_activity',
    ), $dbOptions);
}



/**
 * Session open handler
 * @param string Path to save session to
 * @param string Name of the session
 */
public function open($save_path, $session_name) {
    // Nothing
    return true;
}

/**
 * Session close handler
 */
public function close() {
    // Nothing
    return true;
}

/**
 * Session load handler. Load the session
 * @param string Session ID
 */
public function read($session_id) {
    // Load Table from the database
    $dbTable   = $this->dbOptions['db_table'];
    $dbDataCol = $this->dbOptions['db_data_col'];
    $dbIdCol   = $this->dbOptions['db_id_col'];
    // Load the session data from the database
    $query = $this->pdo->prepare("
        SELECT $dbDataCol
        FROM $dbTable
        WHERE $dbIdCol = :session_id");
    $query->execute(array(':session_id' => $session_id));

    return $query->fetchColumn();
}

/**
 * Session save handler. Save the session
 * @param string Session ID
 * @param string Data to save to session
 */
public function write($session_id, $data) {

    //load table form the database
    $dbTable   = $this->dbOptions['db_table'];
    $dbDataCol = $this->dbOptions['db_data_col'];
    $dbIdCol   = $this->dbOptions['db_id_col'];
    $dbTimeCol = $this->dbOptions['db_time_col'];

    /* Try to update the existing session. If we can't find one, then create a new one. If you
     * are using MySQL, this can be done in a single INSERT statment via INSERT ... ON 
     * DUPLICATE KEY UPDATE. Remove the UPDATE and edit the INSERT to do it this way.
     * See http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
     *
     * This does two queries so you can use any DBMS.
     */

    $query = $this->pdo->prepare("
        UPDATE $dbTable
        SET $dbDataCol = :data, last_activity = :last_activity
        WHERE $dbIdCol = :session_id");
    $query->execute(array(
        ":session_id" => $session_id,
        ":data" => $data,
        "$dbTimeCol" => time()));

    // No session to update? Create a new one
    if ($query->rowCount() == 0) {
        $query = $this->pdo
                ->prepare('
                INSERT INTO sessions
                    (session_id, data, last_activity)
                VALUES
                    (:session_id, :data, :last_activity)')
                ->execute(array(
                    ':session_id' => $session_id,
                    ':data' => $data,
                    'last_activity' => time())
        );
    }
}

/**
 * Session delete handler. Delete the session from the database
 * @param string Session ID
 */
public function destroy($session_id) {
    //Load Table from the database
    $dbTable   = $this->dbOptions['db_table'];
    $dbIdCol   = $this->dbOptions['db_id_col'];

     $this->pdo
            ->prepare("
            DELETE FROM $dbTable
            WHERE $dbIdCol = :session_id")
            ->execute(array(':session_id' => $session_id));
}

/**
 * Session garbage collector. Delete any old expired sessions
 * @param int How many seconds do sessions last for?
 */
public function gc($lifetime) {
    //Load Table from the database
    $dbTable   = $this->dbOptions['db_table'];
    $dbTimeCol = $this->dbOptions['db_time_col'];

    $this->pdo
            ->prepare("
            DELETE FROM $dbTable
            WHERE $dbTimeCol < :min_time")
            ->execute(array(':min_time' => time() - $lifetime));
}

}

希望它能帮助其他人:D

csrf保护在此起作用:
身份验证请求失败:无效的csrf令牌。
使用
$session->isStarted()检查会话是否正确启动。
。顺便说一句,你清除了所有缓存和浏览器缓存吗?是的,我清除了所有缓存和浏览器缓存。。而且$session->isStarted()在我转储它时返回true。。。我还尝试禁用csrf令牌并使身份验证成功,但下一个问题是,当他在成功身份验证后转到主页时,主页会创建另一个会话(仅在PDOSessionHandler中,但在默认的sessionhandler中,它不会创建另一个会话)在这种情况下,令牌再次未经身份验证,并重定向我再次登录。因此,会话处理程序基本上不会拾取以前的会话,因此会为每个请求创建新的会话?基本上,这是我从它提供的日志中看到的。我将更新我的问题,以查看不带csrf令牌的完整日志。日志对此很清楚。每次新请求时都会再次创建会话。够了。你还改变了什么吗?比如重写会话处理程序?
framework:
    session:
        handler_id:  session.handler.pdo
services:
    pdo:
        class: PDO
        arguments:
            dsn:      "mysql:dbname=dev_reporting_system"
            user:     root
            password: null
        calls:
            - [setAttribute, [3, 2]] # \PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION
    session.handler.pdo:
        class:     foor\barBundle\Handler\CustomPdoSessionHandler
        arguments: ["@pdo", "%pdo.db_options%"]