Sammy
Sammy

Reputation: 21

How to disallow multiple parallel user sessions per login in ZF2?

I'm currently facing the situation, that the ZendFramework2 ZFCuser-Module does not have any options to prevent a user from logging in from two devices at the same time.

We recently had a case, that two people were "account-sharing" and accidentally deleted each others data. Since I did not build the application to account for this kind of resource conflicts, I need to prevent this behaviour now.

Is there any module or easy possibility out there to prevent account-sharing in Zend Framework 2 with ZFCUser?

The docs and SO and all sorts of ZF2 blogs somehow appear to never have come across this type of problem...

Thanks in advance!

Upvotes: 2

Views: 435

Answers (1)

rocky
rocky

Reputation: 631

I was able to achieve the functionality of limiting the number of sessions for the same user.

However, my solution (code below) doesn't provide any data-protected layer in order to restrict CRUD operation performed from another session.

I think you can achieve this if you restrict operation based on user_id and session_id

DB

id user_id client_id
00m5nqcvpk9bhqv7rbllq5hsi4 198 14
34ssnqcvpk9xxqv7rbll4354fdf 123 42
id will be session_id (PHP SID)

Method

/**
     * 
     * @param int $userId
     * @param int $clientId
     * @return type
     */
    public function validateActiveSession($userId, $clientId) {
        if (empty($userId)) {
            $userId = $this->getResourceManager()->getIdentity()->getId();
        }

        if (empty($clientId)) {
            $clientId = $this->getResourceManager()->getIdentity()->getClientId();
        }

        $sessionManager = $this->getServiceLocator()->get('Zend\Session\SessionManager');
        $id = $sessionManager->getId();

        $userModel = $this->getResourceManager()->getuserModel();

        $sIdUserExist = $userModel->getUserActiveSession('', '', $id);
        if (empty($sIdUserExist)) {
            $userModel->addUserSessionBySidAndUserClientId($id, $userId, $clientId);
        }
    }

Repository

public function addUserSessionBySidAndUserClientId($sessionId, $userId, $clientId)
    {
        $em = $this->_em->getConnection();
        $sql = "INSERT INTO `user_session`(`id`, `user_id`, `client_id`) VALUES (:id,:user_id,:client_id)";
        $params = array('id' => $sessionId, 'user_id' => $userId, 'client_id' => $clientId);
        $stmt = $em->prepare($sql);
        return $stmt->execute($params);
    }

public function getActiveUserSession($userId, $clientId, $sessionId)
    {
        $rsm = new ResultSetMapping();
        $rsm->addScalarResult('id', 'id');
        $rsm->addScalarResult('user_id', 'user_id');

        $userIdClause = $clientIdClause = $andClause = $sessionIdClause = '';

        if (!empty($userId)) {
            $userIdClause = 'user_id = :user_id';
        }

        if (!empty($clientId)) {
            $clientIdClause = ' and client_id = :client_id';
        }

        if (!empty($userId) && !empty($sessionId)) {
            $andClause = ' and ';
        }

        if (!empty($sessionId)) {
            $sessionIdClause = 'id = :id';
        }

        $query = $this->_em->createNativeQuery('SELECT id,user_id FROM user_session WHERE ' . $userIdClause . $clientIdClause . $andClause . $sessionIdClause, $rsm);

        if (!empty($userId)) {
            $query->setParameter('user_id', $userId);
        }

        if (!empty($clientId)) {
            $query->setParameter('client_id', $clientId);
        }
        if (!empty($sessionId)) {
            $query->setParameter('id', $sessionId);
        }

        return $query->getResult();
    }

once user logged-in check for active sessions

$sameActiveUser = count($userModel->getActiveUserSession($userId, $clientId, ''));
    
if ($sameActiveUser == 2) { //already 2 active session than restrict 3rd
   return "session already present";
} else {
   $this->validateActiveSession($userId, $clientId);
}

Upvotes: 0

Related Questions