add modified function login anda logout
This commit is contained in:
parent
98b1df4f12
commit
e14b2ff46c
|
@ -41,9 +41,9 @@ exports.register = async (req, res) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Penyimpanan sesi login (in-memory)
|
// Inisialisasi global variables di awal file
|
||||||
const activeSessions = {};
|
const activeSessions = {}; // { userId: true }
|
||||||
const sessionTimeouts = {};
|
const sessionTimeouts = {}; // { userId: timeoutId }
|
||||||
|
|
||||||
// Login
|
// Login
|
||||||
exports.login = async (req, res) => {
|
exports.login = async (req, res) => {
|
||||||
|
@ -58,7 +58,10 @@ exports.login = async (req, res) => {
|
||||||
|
|
||||||
// 🔹 Cek apakah user sudah login di device lain
|
// 🔹 Cek apakah user sudah login di device lain
|
||||||
if (activeSessions[user.id]) {
|
if (activeSessions[user.id]) {
|
||||||
return res.status(403).json({ message: "Akun ini sedang digunakan di perangkat lain." });
|
return res.status(403).json({
|
||||||
|
message: "Akun ini sedang digunakan di perangkat lain.",
|
||||||
|
debug: `User ${user.id} masih dalam sesi aktif`
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔹 Verifikasi password
|
// 🔹 Verifikasi password
|
||||||
|
@ -75,42 +78,144 @@ exports.login = async (req, res) => {
|
||||||
);
|
);
|
||||||
|
|
||||||
// 🔹 Tandai user sedang login (aktif)
|
// 🔹 Tandai user sedang login (aktif)
|
||||||
activeSessions[user.id] = true;
|
activeSessions[user.id] = {
|
||||||
|
loginTime: new Date(),
|
||||||
|
email: user.email
|
||||||
|
};
|
||||||
|
|
||||||
// 🔹 Atur timer logout otomatis setelah 5 menit (300000 ms)
|
// 🔹 Bersihkan timeout lama jika ada
|
||||||
if (sessionTimeouts[user.id]) {
|
if (sessionTimeouts[user.id]) {
|
||||||
clearTimeout(sessionTimeouts[user.id]); // Bersihkan timer lama jika ada
|
clearTimeout(sessionTimeouts[user.id]);
|
||||||
|
delete sessionTimeouts[user.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔹 Atur timer logout otomatis setelah 5 menit
|
||||||
sessionTimeouts[user.id] = setTimeout(() => {
|
sessionTimeouts[user.id] = setTimeout(() => {
|
||||||
|
console.log(`User ID ${user.id} (${user.email}) otomatis logout karena timeout`);
|
||||||
delete activeSessions[user.id];
|
delete activeSessions[user.id];
|
||||||
delete sessionTimeouts[user.id];
|
delete sessionTimeouts[user.id];
|
||||||
console.log(`User ID ${user.id} otomatis logout karena timeout`);
|
|
||||||
}, 5 * 60 * 1000); // 5 menit
|
}, 5 * 60 * 1000); // 5 menit
|
||||||
|
|
||||||
console.log("User ID dari backend:", user.id);
|
console.log("Login berhasil - User ID:", user.id, "Email:", user.email);
|
||||||
|
console.log("Active sessions:", Object.keys(activeSessions));
|
||||||
|
|
||||||
// 🔹 Kirim response
|
// 🔹 Kirim response
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
message: "Login berhasil",
|
message: "Login berhasil",
|
||||||
token,
|
token,
|
||||||
role: user.role
|
role: user.role,
|
||||||
|
userId: user.id
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({ message: "Terjadi kesalahan", error });
|
console.error("Login error:", error);
|
||||||
|
res.status(500).json({ message: "Terjadi kesalahan", error: error.message });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//logout
|
// Logout (Versi yang lebih robust)
|
||||||
exports.logout = async (req, res) => {
|
exports.logout = async (req, res) => {
|
||||||
const userId = req.user?.id;
|
try {
|
||||||
|
// Coba ambil userId dari berbagai sumber
|
||||||
|
let userId = req.user?.id;
|
||||||
|
|
||||||
|
// Jika tidak ada dari middleware, coba ambil dari body atau query
|
||||||
|
if (!userId) {
|
||||||
|
userId = req.body?.userId || req.query?.userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jika masih tidak ada, coba decode token manual
|
||||||
|
if (!userId && req.headers.authorization) {
|
||||||
|
try {
|
||||||
|
const token = req.headers.authorization.split(' ')[1];
|
||||||
|
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
||||||
|
userId = decoded.id;
|
||||||
|
} catch (tokenError) {
|
||||||
|
console.log("Token decode error:", tokenError.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Logout attempt - User ID:", userId);
|
||||||
|
console.log("Active sessions before logout:", Object.keys(activeSessions));
|
||||||
|
|
||||||
if (userId && activeSessions[userId]) {
|
if (userId && activeSessions[userId]) {
|
||||||
|
// Hapus sesi aktif
|
||||||
delete activeSessions[userId];
|
delete activeSessions[userId];
|
||||||
|
|
||||||
|
// Bersihkan timeout
|
||||||
|
if (sessionTimeouts[userId]) {
|
||||||
clearTimeout(sessionTimeouts[userId]);
|
clearTimeout(sessionTimeouts[userId]);
|
||||||
delete sessionTimeouts[userId];
|
delete sessionTimeouts[userId];
|
||||||
return res.status(200).json({ message: "Logout berhasil" });
|
|
||||||
}
|
}
|
||||||
res.status(400).json({ message: "Tidak ada sesi login aktif" });
|
|
||||||
|
console.log("Logout berhasil - User ID:", userId);
|
||||||
|
console.log("Active sessions after logout:", Object.keys(activeSessions));
|
||||||
|
|
||||||
|
return res.status(200).json({
|
||||||
|
message: "Logout berhasil",
|
||||||
|
userId: userId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Logout gagal - Tidak ada sesi aktif untuk User ID:", userId);
|
||||||
|
res.status(400).json({
|
||||||
|
message: "Tidak ada sesi login aktif",
|
||||||
|
userId: userId,
|
||||||
|
activeSessions: Object.keys(activeSessions)
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Logout error:", error);
|
||||||
|
res.status(500).json({ message: "Terjadi kesalahan saat logout", error: error.message });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Tambahkan endpoint untuk debugging (opsional - hapus di production)
|
||||||
|
exports.debugSessions = (req, res) => {
|
||||||
|
res.json({
|
||||||
|
activeSessions: activeSessions,
|
||||||
|
sessionTimeouts: Object.keys(sessionTimeouts),
|
||||||
|
message: "Debug info - hapus endpoint ini di production"
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Force logout (untuk admin atau debugging)
|
||||||
|
exports.forceLogout = (req, res) => {
|
||||||
|
const { userId } = req.body;
|
||||||
|
|
||||||
|
if (userId && activeSessions[userId]) {
|
||||||
|
delete activeSessions[userId];
|
||||||
|
if (sessionTimeouts[userId]) {
|
||||||
|
clearTimeout(sessionTimeouts[userId]);
|
||||||
|
delete sessionTimeouts[userId];
|
||||||
|
}
|
||||||
|
return res.json({ message: `User ${userId} berhasil di-force logout` });
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(404).json({ message: "User tidak ditemukan dalam sesi aktif" });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Clear semua sessions (untuk debugging)
|
||||||
|
exports.clearAllSessions = (req, res) => {
|
||||||
|
const sessionCount = Object.keys(activeSessions).length;
|
||||||
|
|
||||||
|
// Bersihkan semua timeout
|
||||||
|
Object.keys(sessionTimeouts).forEach(userId => {
|
||||||
|
clearTimeout(sessionTimeouts[userId]);
|
||||||
|
delete sessionTimeouts[userId];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bersihkan semua active sessions
|
||||||
|
Object.keys(activeSessions).forEach(userId => {
|
||||||
|
delete activeSessions[userId];
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Cleared ${sessionCount} active sessions`);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
message: "Semua sesi aktif berhasil dibersihkan",
|
||||||
|
clearedSessions: sessionCount
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,17 +74,196 @@ router.post('/register', authController.register);
|
||||||
* responses:
|
* responses:
|
||||||
* 200:
|
* 200:
|
||||||
* description: Login berhasil
|
* description: Login berhasil
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* example: Login berhasil
|
||||||
|
* token:
|
||||||
|
* type: string
|
||||||
|
* example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||||
|
* role:
|
||||||
|
* type: string
|
||||||
|
* example: user
|
||||||
|
* userId:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
* 401:
|
* 401:
|
||||||
* description: Password salah
|
* description: Email atau password salah
|
||||||
* 403:
|
* 403:
|
||||||
* description: Akun sedang digunakan di perangkat lain
|
* description: Akun sedang digunakan di perangkat lain
|
||||||
* 404:
|
* content:
|
||||||
* description: User tidak ditemukan
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* example: Akun ini sedang digunakan di perangkat lain.
|
||||||
|
* debug:
|
||||||
|
* type: string
|
||||||
|
* example: User 1 masih dalam sesi aktif
|
||||||
* 500:
|
* 500:
|
||||||
* description: Terjadi kesalahan server
|
* description: Terjadi kesalahan server
|
||||||
*/
|
*/
|
||||||
router.post('/login', authController.login);
|
router.post('/login', authController.login);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/auth/logout:
|
||||||
|
* post:
|
||||||
|
* summary: Logout dari akun
|
||||||
|
* tags: [Authentication]
|
||||||
|
* security:
|
||||||
|
* - bearerAuth: []
|
||||||
|
* requestBody:
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* userId:
|
||||||
|
* type: integer
|
||||||
|
* description: ID user (opsional, diambil dari token jika tidak disediakan)
|
||||||
|
* example: 1
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Logout berhasil
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* example: Logout berhasil
|
||||||
|
* userId:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* 400:
|
||||||
|
* description: Tidak ada sesi login aktif
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* example: Tidak ada sesi login aktif
|
||||||
|
* userId:
|
||||||
|
* type: integer
|
||||||
|
* example: 1
|
||||||
|
* activeSessions:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* type: string
|
||||||
|
* example: ["2", "3"]
|
||||||
|
* 500:
|
||||||
|
* description: Terjadi kesalahan server
|
||||||
|
*/
|
||||||
|
router.post('/logout', authController.logout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/auth/debug-sessions:
|
||||||
|
* get:
|
||||||
|
* summary: Debug - Lihat semua sesi aktif (HAPUS DI PRODUCTION!)
|
||||||
|
* tags: [Debug]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Informasi debug sesi
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* activeSessions:
|
||||||
|
* type: object
|
||||||
|
* description: Objek berisi semua sesi aktif
|
||||||
|
* example:
|
||||||
|
* "1":
|
||||||
|
* loginTime: "2024-01-01T10:00:00.000Z"
|
||||||
|
* email: "johndoe@gmail.com"
|
||||||
|
* sessionTimeouts:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* type: string
|
||||||
|
* description: Array ID user yang memiliki timeout aktif
|
||||||
|
* example: ["1", "2"]
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* example: Debug info - hapus endpoint ini di production
|
||||||
|
*/
|
||||||
|
router.get('/debug-sessions', authController.debugSessions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/auth/force-logout:
|
||||||
|
* post:
|
||||||
|
* summary: Debug - Force logout user tertentu (HAPUS DI PRODUCTION!)
|
||||||
|
* tags: [Debug]
|
||||||
|
* requestBody:
|
||||||
|
* required: true
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* required:
|
||||||
|
* - userId
|
||||||
|
* properties:
|
||||||
|
* userId:
|
||||||
|
* type: integer
|
||||||
|
* description: ID user yang akan di-force logout
|
||||||
|
* example: 1
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Force logout berhasil
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* example: User 1 berhasil di-force logout
|
||||||
|
* 404:
|
||||||
|
* description: User tidak ditemukan dalam sesi aktif
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* example: User tidak ditemukan dalam sesi aktif
|
||||||
|
*/
|
||||||
|
router.post('/force-logout', authController.forceLogout);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/auth/clear-all-sessions:
|
||||||
|
* post:
|
||||||
|
* summary: Debug - Bersihkan semua sesi aktif (HAPUS DI PRODUCTION!)
|
||||||
|
* tags: [Debug]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Semua sesi berhasil dibersihkan
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* message:
|
||||||
|
* type: string
|
||||||
|
* example: Semua sesi aktif berhasil dibersihkan
|
||||||
|
* clearedSessions:
|
||||||
|
* type: integer
|
||||||
|
* example: 3
|
||||||
|
*/
|
||||||
|
router.post('/clear-all-sessions', authController.clearAllSessions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
|
|
|
@ -223,6 +223,8 @@ Future<List<Map<String, dynamic>>> getAllHistori() async {
|
||||||
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
final SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
print("User ID dari respons login: ${responseData['userId']}"); // Tambahkan log
|
print("User ID dari respons login: ${responseData['userId']}"); // Tambahkan log
|
||||||
await prefs.setString('userId', responseData['userId'].toString());
|
await prefs.setString('userId', responseData['userId'].toString());
|
||||||
|
await prefs.setString('token', responseData['token']);
|
||||||
|
await prefs.setString('role', responseData['role']);
|
||||||
|
|
||||||
return responseData;
|
return responseData;
|
||||||
} else {
|
} else {
|
||||||
|
@ -239,6 +241,7 @@ Future<List<Map<String, dynamic>>> getAllHistori() async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
await prefs.remove('token');
|
await prefs.remove('token');
|
||||||
await prefs.remove('role');
|
await prefs.remove('role');
|
||||||
|
await prefs.remove('userId');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fungsi Cek Login
|
// Fungsi Cek Login
|
||||||
|
|
|
@ -5,19 +5,48 @@ import 'riwayat_diagnosa_page.dart';
|
||||||
import 'profile_page.dart';
|
import 'profile_page.dart';
|
||||||
import 'basis_pengetahuan_page.dart';
|
import 'basis_pengetahuan_page.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
import 'login_page.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
class HomePage extends StatefulWidget {
|
class HomePage extends StatefulWidget {
|
||||||
|
|
||||||
|
const HomePage({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_HomePageState createState() => _HomePageState();
|
_HomePageState createState() => _HomePageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomePageState extends State<HomePage> {
|
class _HomePageState extends State<HomePage> {
|
||||||
String userId = ''; // Variabel untuk menyimpan userId
|
String userId = ''; // Variabel untuk menyimpan userId
|
||||||
|
Timer? _logoutTimer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
_startAutoLogoutTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _startAutoLogoutTimer() {
|
||||||
|
_logoutTimer?.cancel(); // Pastikan timer sebelumnya di-cancel
|
||||||
|
|
||||||
|
_logoutTimer = Timer(const Duration(minutes: 5), () async {
|
||||||
|
// Hapus semua data login
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
await prefs.clear();
|
||||||
|
|
||||||
|
// Redirect ke LoginPage
|
||||||
|
if (!mounted) return;
|
||||||
|
Navigator.of(context).pushAndRemoveUntil(
|
||||||
|
MaterialPageRoute(builder: (context) => LoginPage()),
|
||||||
|
(route) => false, // Menghapus semua halaman sebelumnya
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_logoutTimer?.cancel();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> navigateToRiwayatDiagnosaPage(BuildContext context) async {
|
Future<void> navigateToRiwayatDiagnosaPage(BuildContext context) async {
|
||||||
|
|
Loading…
Reference in New Issue