ปัญหานี้เกิดขึ้นเมื่อสมาชิก (user) เดียว แต่สามารถ login เข้าระบบได้จากหลายๆ เครื่อง หลายๆ browser ทำให้ไม่สามารถควบคุมการใช้งานได้ เช่น user A เข้าเรียนหลักสูตร aaa ได้ จากนั้น user A เอา username และ password ไปแจกเพื่อนๆ 9 คน ซึ่งแต่ละคนก็จะสามารถ login เข้ามาเรียนหลักสูตร aaa ได้ ทำให้เกิดปัญหาและความเสียหายต่อผู้ให้บริการ
แนวทางการแก้ไขคือ เมื่อ user A login ให้ทำการลบ session อื่นๆ ที่กำลัง login ออกทั้งหมด และการแก้ไขในปัญหานี้สำหรับ Yii Framework จะใช้ Session ที่เก็บใน Database เป็นตัวจัดการนั่นเอง เริ่มกันเลย
สร้าง migration กันก่อนนะ
cmd
yii migrate/create create_session_table
จากนั้นแก้ไขไฟล์ที่สร้างขึ้นใน console/migrations/xxxx_xxxx_create_session_table.php ดังนี้
<?php
use yii\db\Migration;
/**
* Handles the creation of table `session`.
*/
class m170927_114732_create_session_table extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('session', [
'id' => $this->char(40)->notNull(),
'expire' => $this->integer(),
'data' => $this->binary(),
'user_id' => $this->integer()
]);
$this->addPrimaryKey('session_pk', 'session', 'id');
}
/**
* @inheritdoc
*/
public function down()
{
$this->dropTable('session');
}
}
cmd ประมวลผล
yii migrate
จากนั้นทำการ generate model ด้วย gii generator เก็บไว้ใน common\models\Session.php
จากนั้นแก้ไขการตั้งค่า session ในส่วน components เพื่อให้เรียกใช้ session ใน database โดยแก้ไข frontend/config/main.php เพิ่มเติมส่วน session ใน components
//....
'components' => [
//...
'session' => [
'name' => 'EOFFICE',
'class' => 'yii\web\DbSession',
'sessionTable' => 'session',//ชื่อตารางเก็บ session
'writeCallback' => function($session){
return [
'user_id' => Yii::$app->user->id//กำหนด user_id
];
}
],
//...
]
จากนั้นปรับแต่ง actionLogin() ใน frontend/controllers/SiteController.php เพื่อให้ลบ Session จากเครื่อง/browser อื่นๆ ดังนี้
public function actionLogin()
{
//$this->layout = 'login';
if (!Yii::$app->user->isGuest) {
return $this->goHome();
}
$model = new LoginForm();
if ($model->load(Yii::$app->request->post()) && $model->login()) {
Session::deleteAll(['and', 'user_id = '.Yii::$app->user->getId(), "id != '".Yii::$app->session->id."'"]); //ส่วนที่เพิ่มเติม อย่าลืม use common\models\Session; ก่อนล่ะ
return $this->goBack();
} else {
return $this->render('login', [
'model' => $model,
]);
}
}
ทดสอบโดยการ login จากหลายๆ browser จากนั้น ลอง refresh แต่ละ browser จะเหลือ login concurrent เพียงที่ login ใน browser ตัวล่าสุดนั่นเอง
หมายเหตุ ต้องไม่เลือก remember me นะครับ
นี่เป็นเพียงวิธีการหนึ่งเท่านั้น หากเพื่อนๆ มีทางอื่นๆ ที่ดีกว่าช่วยแจ้งด้วยนะครับ
ความคิดเห็น