update user login baru dan hakakses

This commit is contained in:
Fanrouver
2025-12-16 10:42:45 +07:00
parent 78de0418e1
commit d2a51f3aee
24 changed files with 2606 additions and 189 deletions
+166
View File
@@ -0,0 +1,166 @@
// server/api/users/list.get.ts
// Get all users from database and enrich with last access from Keycloak
import Database from 'better-sqlite3';
import { join } from 'path';
import { existsSync, mkdirSync } from 'fs';
// Helper to get database path
const getDbPath = () => {
const dbDir = join(process.cwd(), 'data');
if (!existsSync(dbDir)) {
mkdirSync(dbDir, { recursive: true });
}
return join(dbDir, 'users.db');
};
// Helper to decode JWT token payload
const decodeTokenPayload = (token: string | undefined): any | null => {
if (!token) return null;
try {
const parts = token.split(".");
if (parts.length < 2) return null;
const payloadBase64 = parts[1];
return JSON.parse(Buffer.from(payloadBase64, "base64").toString());
} catch (e) {
return null;
}
};
// Helper to get last access from Keycloak for a user using access token from session
const getLastAccessFromKeycloak = async (userId: string, accessToken: string, config: any): Promise<number | null> => {
try {
if (!accessToken) {
return null;
}
// Extract realm from issuer
const issuerUrl = new URL(config.keycloakIssuer);
const realm = issuerUrl.pathname.split('/').filter(Boolean).pop() || 'master';
// Get user sessions from Keycloak Admin API using access token
const sessionsUrl = `${config.keycloakIssuer.replace('/realms/' + realm, '')}/admin/realms/${realm}/users/${userId}/sessions`;
const sessionsResponse = await fetch(sessionsUrl, {
method: 'GET',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json',
},
});
if (!sessionsResponse.ok) {
if (sessionsResponse.status === 404 || sessionsResponse.status === 403) {
// User has no sessions or no permission
return null;
}
return null;
}
const sessions = await sessionsResponse.json() as any[];
if (!sessions || sessions.length === 0) {
return null;
}
// Find the most recent session (highest lastAccess timestamp)
let lastAccessTimestamp = 0;
sessions.forEach(session => {
if (session.lastAccess && session.lastAccess > lastAccessTimestamp) {
lastAccessTimestamp = session.lastAccess;
}
});
// Convert from milliseconds to seconds (Unix timestamp)
return lastAccessTimestamp > 0 ? Math.floor(lastAccessTimestamp / 1000) : null;
} catch (error: any) {
console.warn(`⚠️ Error fetching last access for user ${userId}:`, error.message);
return null;
}
};
export default defineEventHandler(async (event) => {
console.log("📋 Users list endpoint called");
try {
const config = useRuntimeConfig();
const dbPath = getDbPath();
// Check if database exists
if (!existsSync(dbPath)) {
console.log("️ Database not found, returning empty array");
return [];
}
// Try to get access token from current user session
let accessToken: string | null = null;
try {
const sessionCookie = getCookie(event, "user_session");
if (sessionCookie) {
const session = JSON.parse(sessionCookie);
const isExpired = Date.now() > session.expiresAt;
if (!isExpired && session.accessToken) {
accessToken = session.accessToken;
}
}
} catch (e) {
// No session available, will skip Keycloak fetch
console.log("️ No valid session found, will use database values for last access");
}
const db = new Database(dbPath);
// Get all users
const users = db.prepare('SELECT * FROM users ORDER BY updatedAt DESC').all() as any[];
// Parse JSON fields and enrich with last access from Keycloak
const formattedUsers = await Promise.all(users.map(async (user) => {
// Try to get last access from Keycloak, fallback to database value
let lastLogin = user.lastLogin || null;
// Only fetch from Keycloak if we have a valid user ID, access token, and config
if (user.id && accessToken && config.keycloakIssuer) {
try {
const keycloakLastAccess = await getLastAccessFromKeycloak(user.id, accessToken, config);
// Use Keycloak last access if available, otherwise keep database value
if (keycloakLastAccess) {
lastLogin = keycloakLastAccess;
}
} catch (error) {
// Silently fail and use database value
console.warn(`⚠️ Could not fetch last access for user ${user.id}, using database value`);
}
}
return {
id: user.id,
namaLengkap: user.namaLengkap,
namaUser: user.namaUser,
email: user.email,
tipeUser: user.tipeUser || '',
lastLogin: lastLogin,
roles: JSON.parse(user.roles || '[]'),
realmRoles: JSON.parse(user.realmRoles || '[]'),
accountRoles: JSON.parse(user.accountRoles || '[]'),
resourceRoles: JSON.parse(user.resourceRoles || '[]'),
groups: JSON.parse(user.groups || '[]'),
given_name: user.given_name,
family_name: user.family_name,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
};
}));
db.close();
console.log(`✅ Retrieved ${formattedUsers.length} users with last access data`);
return formattedUsers;
} catch (error: any) {
console.error("❌ Error fetching users:", error);
throw createError({
statusCode: 500,
statusMessage: error.message || "Failed to fetch users",
});
}
});