เนื้อหานี้เป็นแนวทางเพิ่มเติม สำหรับการประยุกต์ใช้งานระบบสมาชิก
ใน app ionic material ร่วมกับ SQLite plugin เนื้อหาเพิ่มเติมจากตอนที่
ผ่านมา เนื่องจากระบบของเรามีการสมัครสมาชิก และเก็บเข้าไปใน database
เราพบว่า ในการเข้าใช้งานทุกๆ ครั้งที่เปิด app ขึ้นมาใหม่ ระบบจะไปที่หน้า
ล็อกอิน เพื่อให้สมาชิกทำการล็อกอินเข้ามาใช้งานใหม่ทุกๆ ครั้ง ดังนั้น
ในที่นี้ จะแสดงวิธีการกำหนดให้ app ของเราจำค่าข้อมูลของสมาชิกไว้ใน
ตารางที่เราจะสร้างขึ้นมา และเมื่อผู้ใช้ไม่ได้ทำการล็อกเอาท์ออกจากระบบ
และเปิด app เข้ามาอีกครั้งจะสามารถเข้าไปในระบบได้อัตโนมัติ
บทความต่อจากตอนที่แล้ว
ประยุกต์ใช้งาน ระบบสมาชิกใน app ionic material ร่วมกับ SQLite
https://www.ninenik.com/content.php?arti_id=735 via @ninenik
ขั้นตอนปรับแต่งระบบสมาชิกเพิ่มเติมเป็นแนวทาง
1. กำหนดฟังก์ชั่นล็อกเอาท์ ออกจากระบบให้กับปุ่ม Logout
จากบทความที่ผ่านมา ลิ้งค์สำหรับล็อกเอาท์ของเราจะเป็นการแค่เปลี่ยนหน้า
ไปยังหน้าล็อกอิน และล้างค่า member_id เท่านั้น แต่การประยุกต์เพิ่มเติม เราจะ
ให้เป็นการเรียกใช้ฟังก์ชัน logoutMember() ที่จะสร้างขึ้น
เปิดไฟล์ menu.html ในโฟลเดอร์ templates แก้ไขเมนู Logout เป็นดังนี้
<ion-item ng-click="logoutMember()" ng-show="showMemberMenu" nav-clear menu-close > Logout </ion-item>
2. จัดการในส่วนควบคุม controller การทำงานของ app
AppCtrl ส่วนของ controller หลัก
.controller('AppCtrl', function($scope, $ionicModal, $ionicPopover, $timeout, $ionicPopup,$ionicPlatform, $cordovaDialogs, $cordovaToast, $state ) { $scope.loginData = {}; $scope.isExpanded = false; $scope.hasHeaderFabLeft = false; $scope.hasHeaderFabRight = false; var navIcons = document.getElementsByClassName('ion-navicon'); for (var i = 0; i < navIcons.length; i++) { navIcons.addEventListener('click', function() { this.classList.toggle('active'); }); } //////////////////////////////////////// // Layout Methods //////////////////////////////////////// $scope.hideNavBar = function() { document.getElementsByTagName('ion-nav-bar')[0].style.display = 'none'; }; $scope.showNavBar = function() { document.getElementsByTagName('ion-nav-bar')[0].style.display = 'block'; }; $scope.noHeader = function() { var content = document.getElementsByTagName('ion-content'); for (var i = 0; i < content.length; i++) { if (content[i].classList.contains('has-header')) { content[i].classList.toggle('has-header'); } } }; $scope.setExpanded = function(bool) { $scope.isExpanded = bool; }; $scope.setHeaderFab = function(location) { var hasHeaderFabLeft = false; var hasHeaderFabRight = false; switch (location) { case 'left': hasHeaderFabLeft = true; break; case 'right': hasHeaderFabRight = true; break; } $scope.hasHeaderFabLeft = hasHeaderFabLeft; $scope.hasHeaderFabRight = hasHeaderFabRight; }; $scope.hasHeader = function() { var content = document.getElementsByTagName('ion-content'); for (var i = 0; i < content.length; i++) { if (!content[i].classList.contains('has-header')) { content[i].classList.toggle('has-header'); } } }; $scope.hideHeader = function() { $scope.hideNavBar(); $scope.noHeader(); }; $scope.showHeader = function() { $scope.showNavBar(); $scope.hasHeader(); }; $scope.clearFabs = function() { var fabs = document.getElementsByClassName('button-fab'); if (fabs.length && fabs.length > 1) { fabs[0].remove(); } }; $scope.noShadow = function() { var headerBar = document.getElementsByTagName('ion-header-bar'); for (var i = 0; i < headerBar.length; i++) { if (!headerBar[i].classList.contains('no-shadow')) { headerBar[i].classList.add('no-shadow'); } } }; $scope.hasShadow = function() { var headerBar = document.getElementsByTagName('ion-header-bar'); for (var i = 0; i < headerBar.length; i++) { if (headerBar[i].classList.contains('no-shadow')) { headerBar[i].classList.remove('no-shadow'); } } }; // ตัวแปรสำหรับกำหนด การซ่อนหรือแสดงเมนูสมาชิก false คือซ่อนเมนูสมาชิก $scope.showMemberMenu = false; // สร้างฟังก์ชั่น สำหรับเรียกใช้ เพื่อกำหนดการ กำหนดค่าตัวแปรเพื่อซ่อนหรือแสดงเมนู $scope.setMemberMenu = function(status){ $scope.showMemberMenu = status; }; // กำหนดตัวแปรไว้สำหรับเก็บ id ของสมาชิกที่สมัครในเครื่องนั้นๆ $scope.sesMemberID = null; // สร้างฟังก์ชั่นสำหรับกำหนดค่า id ให้สามารถเรียกใช้งานจาก $scope หลักได้ $scope.setMemberID = function(memID){ $scope.sesMemberID = memID; }; // สร้างฟังก์ชั่นสำหรับเรียกดูค่า id ของสมาชิกจาก $scope หลักได้ $scope.getMemberID = function(){ return $scope.sesMemberID; }; // สร้างฟังก์ชั่นสำหรับเรียกใช้ Toast plugin $scope.showToast = function(str, duration, position){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin return $cordovaToast .show(str, duration, position) .then(function(success) { // success }, function (error) { // error }); }); }; var db = null; $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบและทำการเชื่อมต่อกับ db db = window.sqlitePlugin.openDatabase({ name: 'my.db', location: 'default' }, function (db) { // เชื่อมต่อ db สำเร็จ $scope.showToast('Open DB Success','long','bottom'); // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // เวลามีการทดสอบและเพิ่มฟิลด์หรือแก้ไขตารางควรเปิดคอมเม้นการลบตารางก่อน // นั้นหมายถึงตารางจะถูกสร้างและจัดรูปแบบใหม่ทุกครั้ง ข้อมูลตารางจะรีเซ็ต ล้างค่า // พอว่างโครงสร้างตารางเรียบร้อยแล้ว ให้ปิดคอมเม้นไว้เหมือนเดิม เพื่อให้ข้อมูลยังคงอยู่ // tx.executeSql('DROP TABLE IF EXISTS setting'); // ทำคำสั่งสร้างตาราง setting ถ้ายังไม่มี ในที่นี้เราเก็บแค่ setting_id และ member_id tx.executeSql('' + 'CREATE TABLE IF NOT EXISTS setting ' + '(setting_id integer primary key,' + 'member_id integer)' + ''); // เช็คตาราง setting ว่ามีข้อมูลไหม tx.executeSql("SELECT setting_id,member_id FROM setting ", [], function(tx, res) { if(res.rows.length<=0){ // ถ้าไม่มีข้อมูล ให้เพิ่มข้อมูลไป var query = "INSERT INTO setting" + " (member_id) " + " VALUES (?)"; var member_id = 0; // ทำงานคำสั่ง sql tx.executeSql(query, [member_id], function(tx, res) { // เมื่อทำการบันทึกข้อมูลสำเร็จ // ค่าเริ่มต้น เราจะให้ member_id เป็น 0 ไว้ก่อน แล้วค่อยมาอัพเเดทที่หลัง $scope.showToast('insertId: ' + res.insertId + ' -- probably 1','long','bottom'); $scope.showToast('rowsAffected: ' + res.rowsAffected + ' -- should be 1','long','bottom'); }, function(tx, error) { $scope.showToast('INSERT error: ' + error.message,'long','bottom'); }); }else{ // ถ้ามีข้อมูลอยู่แล้ว และ member_id ที่เก็บไว้ไม่เท่ากับ 0 if(res.rows.item(0).member_id!=0){ // เช็ค member_id ที่เก็ยไว้ไม่เท่ากับ 0 $scope.setMemberID(res.rows.item(0).member_id); // กำหนดค่าตัวแปร $state.go('app.profile'); // ไปที่หน้าโพรไฟล์ } } }); }, function (error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function () { $scope.showToast('transaction ok','long','bottom'); }); }, function (error) { $scope.showToast('Open database ERROR: ' + JSON.stringify(error),'long','bottom'); }); }); // สร้างฟังก์ชั่นสำหรับ logout $scope.logoutMember = function(){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ขึ้นแจ้งเตือนว่าต้องการจะออกจากระบบหรือไม่ $cordovaDialogs.confirm('ยืนยันออกจากระบบ?', 'ออกจากระบบ?', ['ตกลง','ยกเลิก']) .then(function(buttonIndex) { // no button = 0, 'OK' = 1, 'Cancel' = 2 var btnIndex = buttonIndex; if(btnIndex==2){ // ถ้าตอบ ยกเลิก return false; // หยุดการทำงาน ไม่ต้องออกจากระบบ } if(btnIndex==1){ // ถ้าตอบ ตกลง ยืนบันออกจากรับบ // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // ล้างค่า member_id ที่บันทึกไว้ในตาราง setting ให้เป็น 0 คือไม่จำ member_id var query = "UPDATE setting SET member_id = 0 WHERE setting_id = 1"; tx.executeSql(query); $scope.sesMemberID = null; $state.go('app.login'); // ไปที่หน้าล็อกอิน }, function(error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function() { $scope.showToast('transaction ok','long','bottom'); }); } }); }); }; })
จากโค้ดข้างต้น ใน AppCtrl มีการเรียกใช้ plugin SQLite และ plugin อื่นที่เกี่ยวข้าง เหมือน
กับทีเราเคยกำหนดใน LoginCtrl , RegistCtrl และ ProfileCtrl ส่วนที่เพิ่มมาในการทำงานส่วนของ
controller หลักคือ เชื่อมต่อกับ database และสร้างตาราง setting ถ้ายังไม่มี เพื่อเก็บ member_id
โดยหากยังไม่มีตาราง ให้ทำการสร้างตาราง และ insert ข้อมูลค่าเริ่มต้นเข้าไปในตาราง เก็บค่า
member_id เป็น 0 แต่ถ้ามีตาราง และมีข้อมูล member_id อยู่แล้ว ให้นำข้อมูลจากตาราง setting
มาใช้ในตัวแปร sesMemberID จากนั้นให้ลิ้งค์หรือล็อกอินอัตโนมัติไปยังหน้าโพรไฟล์
นอกจากนั้นใน AppCtrl ยังมีฟังก์ชั่น logoutMember() ที่เราสามารถ เพื่อเรียกใช้ในเมนู Logout
ที่กล้าวไปแล้วข้างต้น โดยเมื่อถ้าผู้ใช้มีการกดล็อกเอาท์ออกจากระบบใน app ก็จะไปทำการรีเซ็ต
ค่าสมาชิก หรือ member_id ให้เท่ากับ 0 แล้วอัพเดทลงใน database ซึ่งนั้นก็คือ ถ้าสมาชิกกด ออก
จากระบบแล้ว ทุกๆ ครั้งที่เปิด app ขึ้นมาใหม่ สมาชิกจะต้องทำการล็อกอินใหม่เสมอ แต่กรณี้ที่
ไม่ได้กดออกจากระบบ และปิด app ไป แล้วเมื่อเปิด app ขึ้นมาใหม่ ระบบก็จะไปเอาค่า member_id
ที่เก็บไว้ใน database มาทำการล็อกอินให้โดยอัตโนมัติ
LoginCtrl ส่วนของ controller หน้า login
.controller('LoginCtrl', function($scope, $timeout, $stateParams, ionicMaterialInk ,$ionicPlatform, $cordovaDialogs, $cordovaToast, $state) { $scope.$parent.clearFabs(); $scope.$parent.hasShadow(); $timeout(function() { $scope.$parent.hideHeader(); }, 0); // กำนหดค่าเริ่มต้นของฟอร์มหน้าสมัครสมาชิก ให้เป็นค่าว่าง $scope.login = { input_user:'', input_pass:'' }; // เรียกใช้ฟังก์ชั่นจาก AppCtrl หลัก เพื่อซ่อนเมนูสมาชิก โดยส่งค่า false เข้าไป $scope.$parent.setMemberMenu(false); // สร้างฟังก์ชั่นสำหรับเรียกใช้ Toast plugin $scope.showToast = function(str, duration, position){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin return $cordovaToast .show(str, duration, position) .then(function(success) { // success }, function (error) { // error }); }); }; var db = null; $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบและทำการเชื่อมต่อกับ db db = window.sqlitePlugin.openDatabase({ name: 'my.db', location: 'default' }, function (db) { $scope.showToast('Open DB Success','long','bottom'); }, function (error) { $scope.showToast('Open database ERROR: ' + JSON.stringify(error),'long','bottom'); }); }); // สร้างฟังก์ชั่นสำหรับล็อกอิน รับค่า data จาก object login $scope.loginMember = function(data){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบถ้ากรอกข้อมูลไม่ครบ if(data.input_user=="" || data.input_pass==""){ $cordovaDialogs.alert('โปรดกรอกข้อมูลให้ครบถ้วน', 'ข้อมูลจำเป็น', 'ตกลง') .then(function() { return false; }); return false; } // แสดงข้อมูลที่ส่งเข้ามา เวลาใช้จริงสามารถลบออกได้ $scope.showToast(' user: ' + data.input_user + ' pass: ' + data.input_pass +'', 'long', 'bottom'); // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // กำหนดคำสั่ง sql ค่าที่รับมาตรวจสอบ แทนด้วย ? // คำสั่งนี้คือเช็คว่า มีสมาชิกที่ user และ pass ตรงหรือไม่ ตัวเล็กตัวใหญ่มีค่าต่างกัน var query = "SELECT member_id, member_user, member_phone" + " FROM member WHERE member_user = ? AND member_pass = ? "; // ทำคำสั่ง sql ส่งค่าเข้าไปให้ตรงกับจำนวน ในที่นี้มี data.input_user และ data.input_pass tx.executeSql(query, [data.input_user, data.input_pass], function (tx, resultSet) { // ถ้าพบรายการใน db if(resultSet.rows.length){ // นำค่า ID ของสมาชิกไปเก็บในตัวแปร sesMemberID ด้วยฟังก์ชั่น setMemberID // ที่อยู่ใน controller หลัก $scope.$parent.setMemberID(resultSet.rows.item(0).member_id); var query = "UPDATE setting SET member_id = ? WHERE setting_id = 1"; tx.executeSql(query, [resultSet.rows.item(0).member_id]); // ขึ้นแจ้ง เข้าสู่ระบบสำเร็จ และเปลี่ยนไปหน้า profile ด้วย $stat.go() $cordovaDialogs.alert('เข้าสู่ระบบสำเร็จ', 'เข้าสู่ระบบ', 'ตกลง') .then(function() { $state.go('app.profile'); }); }else{ // ไม่พบข้อมูล ขึ้นแจ้งเตือนว่ามีข้อผิดพลาด $cordovaDialogs.alert('ชื่อหรือรหัสผ่านไม่ถูกต้อง', 'เกิดข้อผิดพลาด', 'ตกลง') .then(function() { return false; }); return false; } }, function (tx, error) { // ข้อความแจ้ง SELECT error $scope.showToast('SELECT error: ' + error.message,'long','bottom'); }); }, function(error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function() { $scope.showToast('transaction ok','long','bottom'); }); }); }; ionicMaterialInk.displayEffect(); })
ส่วนที่เพิ่มเข้ามาใน controller หน้าล็อกอินก็คือ การบันทึก member_id ของสมาชิกที่
ทำารล็อกอินสำเร็จไว้ใน database
// อัพเดท member_id เข้าไปในตาราง setting var query = "UPDATE setting SET member_id = ? WHERE setting_id = 1"; tx.executeSql(query, [resultSet.rows.item(0).member_id]);
จากแต่เดิม เราแค่เพียงนำค่าไปกำหนดในตัวแปร sesMemberID ไว้เรียกใช้งานใน app
แล้วลิ้งค์ไปหน้าโพรไฟล์ เราก็ทำการบันทึก member_id ไว้ในตาราง setting ไว้ใช้สำหรับ
เรียกเพื่อทำการนำค่ามาล็อกอินอัตโนมัติ
RegistCtrl ส่วนของ controller หน้า register
.controller('RegistCtrl', function($scope, $timeout, $stateParams, ionicMaterialInk ,$ionicPlatform, $cordovaDialogs, $cordovaToast, $state) { $scope.$parent.clearFabs(); $scope.$parent.hasShadow(); $timeout(function() { $scope.$parent.hideHeader(); }, 0); // กำนหดค่าเริ่มต้นของฟอร์มหน้าสมัครสมาชิก ให้เป็นค่าว่าง $scope.reg = { input_user:'', input_pass:'', input_phone:'' }; // เรียกใช้ฟังก์ชั่นจาก AppCtrl หลัก เพื่อซ่อนเมนูสมาชิก โดยส่งค่า false เข้าไป $scope.$parent.setMemberMenu(false); // สร้างฟังก์ชั่นสำหรับเรียกใช้ Toast plugin $scope.showToast = function(str, duration, position){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin return $cordovaToast .show(str, duration, position) .then(function(success) { // success }, function (error) { // error }); }); }; var db = null; $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบและทำการเชื่อมต่อกับ db db = window.sqlitePlugin.openDatabase({ name: 'my.db', location: 'default' }, function (db) { // เชื่อมต่อ db สำเร็จ $scope.showToast('Open DB Success','long','bottom'); // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // เวลามีการทดสอบและเพิ่มฟิลด์หรือแก้ไขตารางควรเปิดคอมเม้นการลบตารางก่อน // นั้นหมายถึงตารางจะถูกสร้างและจัดรูปแบบใหม่ทุกครั้ง ข้อมูลตารางจะรีเซ็ต ล้างค่า // พอว่างโครงสร้างตารางเรียบร้อยแล้ว ให้ปิดคอมเม้นไว้เหมือนเดิม เพื่อให้ข้อมูลยังคงอยู่ // tx.executeSql('DROP TABLE IF EXISTS member'); // ทำคำสั่งสร้างตาราง member ถ้ายังไม่มี tx.executeSql('' + 'CREATE TABLE IF NOT EXISTS member ' + '(member_id integer primary key,' + 'member_user text, ' + 'member_pass text,' + 'member_phone text)' + ''); }, function (error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function () { $scope.showToast('transaction ok','long','bottom'); }); }, function (error) { $scope.showToast('Open database ERROR: ' + JSON.stringify(error),'long','bottom'); }); }); // สร้างฟังก์ชั่นสำหรับสมัครสมาชิก รับค่า data จาก object reg $scope.registerMember = function(data){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบให้กรอกข้อมูลให้ครบถ้วน if(data.input_user=="" || data.input_pass=="" || data.input_phone==""){ $cordovaDialogs.alert('โปรดกรอกข้อมูลให้ครบถ้วน', 'ข้อมูลจำเป็น', 'ตกลง') .then(function() { return false; }); return false; } // แสดงข้อมูลที่ส่งเข้ามา เวลาใช้จริงสามารถลบออกได้ $scope.showToast(' user: ' + data.input_user + ' pass: ' + data.input_pass + ' phone: ' + data.input_phone +'', 'long', 'bottom'); // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // จัดรูปแบบคำสั่ง sql สำหรับบันทึกข้อมูล ค่าที่รับมาบันทึกจะแทนด้วย ? // ในที่นี้จะส่งมาแค่ 3 ค่า ส่วน member_id นั้นเป็น PRIMARY KEY เป็น auto incremet // โดยอัตโนมัติ var query = "INSERT INTO member" + " (member_user, member_pass, member_phone) " + " VALUES (?,?,?)"; // ทำงานคำสั่ง sql tx.executeSql(query, [data.input_user, data.input_pass, data.input_phone], function(tx, res) { // เมื่อทำการบันทึกข้อมูลสำเร็จ // ใช้ค่า member_id จาก res.insertId แล้วกำหนดค่าด้วยฟังก์ชั่น setMemberID() $scope.$parent.setMemberID(res.insertId); $scope.showToast('insertId: ' + res.insertId + ' -- probably 1','long','bottom'); $scope.showToast('rowsAffected: ' + res.rowsAffected + ' -- should be 1','long','bottom'); // อัพเดท member_id เข้าไปในตาราง setting var query = "UPDATE setting SET member_id = ? WHERE setting_id = 1"; tx.executeSql(query, [res.insertId]); // แจ้งการสมัครสมาชิกสำเร็จ และให้ไปที่หน้า profile $cordovaDialogs.alert('ทำการสัมครสมัครสมาชิกเรียบร้อยแล้ว', 'สมัครสมาชิกใหม่', 'ตกลง') .then(function() { $state.go('app.profile'); }); }, function(tx, error) { $scope.showToast('INSERT error: ' + error.message,'long','bottom'); }); }, function(error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function() { $scope.showToast('transaction ok','long','bottom'); }); }); }; ionicMaterialInk.displayEffect(); })
ในหน้าสมาชิกสมาชิกก็หลักการเดียวกันกับหน้าล็อกอิน คือเมื่อสมัครสมาชิกแล้ว ก็ให้ทำการ
นำ member_id นั้นไปอัพเดทลงตาราง setting ด้วยคำสั่ง
// อัพเดท member_id เข้าไปในตาราง setting var query = "UPDATE setting SET member_id = ? WHERE setting_id = 1"; tx.executeSql(query, [res.insertId]);
แต่จะแตกต่างตรงที่ค่าตัวแปรที่บันทึกลงจะเป็นคนละตัว ในหน้าสมัครสมาชิก จะใช้ member_id
ล่าสุดที่เป็น auto increment บันทึกลง database ส่วนในหน้าล็อกอินจะใช้ค่าที่ไปคิวรี่ดึงมา
ตามเงื่อนไข username และ password ที่ถูกต้อง
3. ทำการ build apk ไฟล์แล้วนำไปทดสอบติดตั้งบนมือถือ
ด้วยคำสั่ง
C:\phonegap\learn001>phonegap build android
การปรับแต่งให้รองรับการล็อกอินอัตโนมัติก็ประมาณนี้ จะเห็นตาราง setting เราจะใช้ข้อมูล
แค่แถวเดียว setting_id จะเท่ากับ 1 เสมอ เราสามารถเพิ่มฟิลด์ของตารางนี้ เพื่อเก็บค่าอื่นๆ
ที่ต้องการตามการนำไปประยุกต์ใช้งานได้
ดาวน์โหลดไฟล์ apk ตัวอย่างได้ที่ https://goo.gl/x6ID7m
การทดสอบก็คือ สมัครสมาชิก หรือล็อกอิน พอเข้าสู่ระบบสำเร็จ ก็ให้ปิด app ไปเลย
โดยไม่ต้อง ออกจากระบบ หรือล็อกเอาท์ และเมื่อพอเราเปิด app กลับเข้ามา ระบบก็จะ
ทำการล็อกอินให้เราอัตโนมัติ