1
votes

I need to manage user sessions in Symfony2.

I have project with long session period.

  1. Show list of all active user sessions. For example: When somebody uses my login/password I want to see it.

  2. Delete some session. For example: If I understand that some session is malefactor, I can delete it.

I found in official Symfony documentation how install custom session handler , but I can't understand how to set user_id there for searching sessions by this parameter.

By default, the table structure for Db session handler:

CREATE TABLE `sessions` (
    `sess_id` VARBINARY(128) NOT NULL PRIMARY KEY,
    `sess_data` BLOB NOT NULL,
    `sess_time` INTEGER UNSIGNED NOT NULL,
    `sess_lifetime` MEDIUMINT NOT NULL
) COLLATE utf8_bin, ENGINE = InnoDB;
1
You have to implement your own custom session handler or find 3rd bundle. Symfony cannot do that for you with default installation. Information about users are in sess_data column in serialized form.kba

1 Answers

1
votes

OK. I found solution!) I take pdo handler and then add two fields (user_id and agent), to find session of current user and show the info about him.

  1. Create custom handler

config.yml

framework:
       handler_id: session.handler.pdo.custom

services.yml

services:
    session.handler.pdo.custom:
        class: YourBundle\HttpFoundation\Session\Storage\Handler\UserIdPdoSessionHandler
        public:    true
        arguments:
            - "pgsql:host=%database_host%;dbname=%database_name%"
            - { db_username: %database_user%, db_password: %database_password% }
            - @security.token_storage

SQL for table

CREATE TABLE sessions (sess_id VARCHAR(128) NOT NULL, sess_data BYTEA NOT NULL, sess_time INT NOT NULL, sess_lifetime INT NOT NULL, user_id INT DEFAULT NULL, server_addr VARCHAR(255) DEFAULT NULL, agent TEXT DEFAULT NULL, PRIMARY KEY(sess_id)) 

Create controller action to show sessions:

/**
 * @Route(name="user_profile_sessions_list", path="/sessions")
 *
 * @param Request $request
 *
 * @return Response
 */
public function sessionsListAction(Request $request)
{
    $user = $this->getUser();
    $sessions = $this->get('session.handler.pdo.custom')->getSessionsByUserId($user->getId());
    return $this->render('YourBundle:Profile:sessions.html.twig', array(
        'sessions' => $sessions,
    ));
}

Create controller action to delete sessions:

/**
 * @Route(name="user_profile_sessions_delete", path="/sessions/delete/{sessionId}")
 *
 * @param Request $request
 *
 * @return Response
 */
public function sessionDeleteAction(Request $request, $sessionId)
{
    $em = $this->getDoctrine()->getManager();

    //Удалим сессию из БД (если это текущая сессия, то сделаем logout)
    if ($sessionId == $this->get('session')->getId()) {
        $redirect = $this->redirect($this->generateUrl('fos_user_security_logout'));
    } else {
        $this->get('session.handler.pdo.custom')->destroy($sessionId, $this->getUser()->getId());
        $redirect = $this->redirect($this->generateUrl('user_profile_sessions_list'));
    }

    return $redirect;
}

If you want you could create Entity:

<?php

namespace Uip\UserBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Sessions
 *
 * @ORM\Table(name="sessions")
 * @ORM\Entity
 */
class Sessions
{
    /**
     * @var string
     * @ORM\Id
     * @ORM\Column(name="sess_id", type="string", length=128, nullable=false)
     */
    private $sessId;

    /**
     * @var string
     * @ORM\Column(name="sess_data", type="blob", nullable=false)
     */
    private $sessData;

    /**
     * @var integer
     * @ORM\Column(name="sess_time", type="integer", nullable=false)
     */
    private $sessTime;

    /**
     * @var integer
     * @ORM\Column(name="sess_lifetime", type="integer", nullable=false)
     */
    private $sessLifetime;

    /**
     * @var integer
     * @ORM\Column(name="user_id", type="integer", nullable=true)
     */
    private $userId;

    /**
     * @var string
     * @ORM\Column(name="server_addr", type="string", nullable=true)
     */
    private $serverAddr;

    /**
     * @var string
     * @ORM\Column(name="agent", type="text", nullable=true)
     */
    private $agent;


    /**
     * Get sessId
     *
     * @return string
     */
    public function getSessId()
    {
        return $this->sessId;
    }

    /**
     * Get sessData
     *
     * @return string
     */
    public function getSessData()
    {
        return $this->sessData;
    }

    /**
     * Set sessData
     *
     * @param string $sessData
     * @return Sessions
     */
    public function setSessData($sessData)
    {
        $this->sessData = $sessData;

        return $this;
    }

    /**
     * Get sessTime
     *
     * @return integer
     */
    public function getSessTime()
    {
        return $this->sessTime;
    }

    /**
     * Set sessTime
     *
     * @param integer $sessTime
     * @return Sessions
     */
    public function setSessTime($sessTime)
    {
        $this->sessTime = $sessTime;

        return $this;
    }

    /**
     * Get sessLifetime
     *
     * @return integer
     */
    public function getSessLifetime()
    {
        return $this->sessLifetime;
    }

    /**
     * Set sessLifetime
     *
     * @param integer $sessLifetime
     * @return Sessions
     */
    public function setSessLifetime($sessLifetime)
    {
        $this->sessLifetime = $sessLifetime;

        return $this;
    }

    /**
     * Get userId
     *
     * @return integer
     */
    public function getUserId()
    {
        return $this->userId;
    }

    /**
     * Set userId
     *
     * @param integer $userId
     * @return Sessions
     */
    public function setUserId($userId)
    {
        $this->userId = $userId;

        return $this;
    }

    /**
     * Get serverAddr
     *
     * @return string
     */
    public function getServerAddr()
    {
        return $this->serverAddr;
    }

    /**
     * Set serverAddr
     *
     * @param string $serverAddr
     * @return Sessions
     */
    public function setServerAddr($serverAddr)
    {
        $this->serverAddr = $serverAddr;

        return $this;
    }

    /**
     * Get agent
     *
     * @return string
     */
    public function getAgent()
    {
        return $this->agent;
    }

    /**
     * Set agent
     *
     * @param string $agent
     * @return Sessions
     */
    public function setAgent($agent)
    {
        $this->agent = $agent;

        return $this;
    }
}

And twig file:

{% extends '@Your/layout.html.twig' %}
{% block content %}
    <h3>{{ 'user.sessions.list' | trans }}</h3>

    <div class="panel panel-default">
        <div class="panel-body">
            <table class="table table-striped">
                {% for session in sessions %}
                    <tr>
                        <td>{{ session.sess_time|date('d.m.Y H:i:s') }}</td>
                        <td>{{ (session.sess_time + session.sess_lifetime)|date('d.m.Y H:i:s') }}</td>
                        <td>{{ session.server_addr }}</td>
                        <td>{{ session.agent }}</td>
                        {% if session.sess_id == app.session.id %}
                            <td><a href="{{ path('fos_user_security_logout') }}" type="button" class="btn btn-danger">Удалить</a>
                                Текущая
                            </td>
                        {% else %}
                            <td><a href="{{ path('user_profile_sessions_delete', {'sessionId' : session.sess_id}) }}"
                                   type="button" class="btn btn-danger">Delete</a></td>
                        {% endif %}
                    </tr>
                {% endfor %}
            </table>

        </div>
    </div>
{% endblock %}