I wanted to logout a user session logged in a different browser/environment from the current session of the same user. A feature similar to this - https://www.facebook.com/settings?tab=security§ion=sessions&view.
Yii2 is the backend framework used. Using redis for session management - yii2-redis. I also save the session ids saved in database.
I followed this article - http://www.codeinphp.com/general/php-code-snippets/remotely-destroy-different-session-php-forced-user-signout/
But didn't had any success.
session_id($old_session_id);
session_start(); // This line throws error.
session_destroy();
Deleting the key in redis using \Yii::$app->session->destroySession($oldSessionId)
didn't logout.
Changing the session id to old one and then destroying the session also didn't work.
$currentSessionId = \Yii::$app->session->getId();
\Yii::$app->session->setId($oldSessionId);
\Yii::$app->getSession()->destroy();
\Yii::$app->session->setId($currentSessionId);
If anyone had success in implementing this successfully, please share your solution. Also if there is any documentation regarding this which can help, please do provide.
The first, session_start()
must be call before session_id()
and just call only once
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
session_id($old_session_id);
session_destroy();
But just remove session, that is not enough if you allow user auto login because browser will auto login by using cookies. To solve, you must change user AuthKey
- Yii2 use AuthKey
to validate user auto login. By default each user have only one AuthKey
in user table so that when you change AuthKey
user logout anywhere. So we have to custom. Create for each user session an AuthKey
, stored somewhere not in user table. Do it easy: extends yii\web\User class override afterLogin
function to create AuthKey
for each login session. override validateAuthKey
function to validate auto login use our custom AuthKey
. Now when you want to kill any user session : kill PHP session id and AuthKey
that session will be logout right away.
I have been using this solution for my projects and it works fine.
Based on Ngo's answer, I figured out a method that works well and is easier to setup.
1) Add a "last_session_id" field to your user table.
2) Add following to your main controller:
public function afterAction($action, $result)
{
$result = parent::afterAction($action, $result);
if(Yii::$app->user->id)
{
//update the user table with last_session_id
$user = User::find()->where(['id' => Yii::$app->user->id])->one();
$user->last_session_id = Yii::$app->session->id;
$user->save(false);
}
return $result;
}
3) Change site/login action to following:
public function actionLogin()
{
if (!\Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
//delete previous session ID and change auth key
Yii::$app->session->destroySession(Yii::$app->user->identity->last_session_id);
$u = \common\models\User::find()->where(['id' => Yii::$app->user->id])->one();
$u->auth_key = Yii::$app->security->generateRandomString();
$u->save(false);
return $this->goBack();
} else {
return $this->render('/site/login', [
'model' => $model,
]);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With