feat: implement user authentication system
- Add SessionManager for managing user sessions (singleton pattern) - Add BIPUsersDAO for database authentication - Add LoginDialog component for username/password login - Add UserSelectionDialog component for admin user selection - Support silent login by computer name - Implement main page with navigation to Extractor and Cleaner Database: - Table: dbo_BIPUsers - Fields: UserName, Password, UserType, ComputerNmae UI Flow: 1. Silent login on startup via computer name 2. Show login dialog if silent login fails 3. Display main page with user info and navigation 4. Support logout and re-login
This commit is contained in:
185
src/main/services/user/session-manager.ts
Normal file
185
src/main/services/user/session-manager.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
/**
|
||||
* User Session Manager - Singleton pattern for managing authenticated user session
|
||||
*
|
||||
* Mimics the Python SessionManager functionality:
|
||||
* - Singleton pattern to maintain user state throughout application lifecycle
|
||||
* - Support for username/password authentication
|
||||
* - Support for silent login by computer name
|
||||
* - Admin user can switch to other users
|
||||
*/
|
||||
|
||||
import type { UserInfo } from '../../types/user.types'
|
||||
|
||||
/**
|
||||
* Session Manager Class
|
||||
*/
|
||||
export class SessionManager {
|
||||
private static instance: SessionManager | null = null
|
||||
private currentUser: UserInfo | null = null
|
||||
private originalAdminUser: UserInfo | null = null
|
||||
private initialized: boolean = false
|
||||
|
||||
private constructor() {
|
||||
if (this.initialized) {
|
||||
return
|
||||
}
|
||||
this.initialized = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the singleton instance
|
||||
*/
|
||||
public static getInstance(): SessionManager {
|
||||
if (SessionManager.instance === null) {
|
||||
SessionManager.instance = new SessionManager()
|
||||
}
|
||||
return SessionManager.instance
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate and login a user
|
||||
* @param username - The username to authenticate
|
||||
* @param password - The password to verify
|
||||
* @returns True if login successful, false otherwise
|
||||
*/
|
||||
public async login(username: string, password: string): Promise<boolean> {
|
||||
try {
|
||||
const { BIPUsersDAO } = await import('./bip-users-dao')
|
||||
const dao = new BIPUsersDAO()
|
||||
const userInfo = await dao.authenticate(username, password)
|
||||
|
||||
if (userInfo) {
|
||||
this.currentUser = {
|
||||
id: userInfo.id,
|
||||
username: userInfo.username,
|
||||
userType: userInfo.userType
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} catch (error) {
|
||||
console.error('[SessionManager] Login error:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt silent login using computer name
|
||||
* @returns True if login successful, false otherwise
|
||||
*/
|
||||
public async loginByComputerName(): Promise<boolean> {
|
||||
try {
|
||||
const { BIPUsersDAO } = await import('./bip-users-dao')
|
||||
const dao = new BIPUsersDAO()
|
||||
const computerName = require('os').hostname()
|
||||
const userInfo = await dao.authenticateByComputerName(computerName)
|
||||
|
||||
if (userInfo) {
|
||||
this.currentUser = {
|
||||
id: userInfo.id,
|
||||
username: userInfo.username,
|
||||
userType: userInfo.userType
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} catch (error) {
|
||||
console.error('[SessionManager] Silent login error:', error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout the current user and clear session
|
||||
*/
|
||||
public logout(): void {
|
||||
this.currentUser = null
|
||||
this.originalAdminUser = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a user is currently authenticated
|
||||
*/
|
||||
public isAuthenticated(): boolean {
|
||||
return this.currentUser !== null
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current user is an admin
|
||||
*/
|
||||
public isAdmin(): boolean {
|
||||
return this.currentUser?.userType === 'Admin'
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current user is a guest
|
||||
*/
|
||||
public isGuest(): boolean {
|
||||
return this.currentUser?.userType === 'Guest'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current username
|
||||
*/
|
||||
public getUsername(): string | null {
|
||||
return this.currentUser?.username ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current user type
|
||||
*/
|
||||
public getUserType(): string | null {
|
||||
return this.currentUser?.userType ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all current user information
|
||||
*/
|
||||
public getUserInfo(): UserInfo | null {
|
||||
return this.currentUser
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to a different user (Admin only feature)
|
||||
* @param userInfo - User info to switch to
|
||||
* @returns True if switch successful
|
||||
*/
|
||||
public switchUser(userInfo: UserInfo): boolean {
|
||||
if (!this.currentUser) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Store original admin user for reference
|
||||
if (!this.originalAdminUser) {
|
||||
this.originalAdminUser = { ...this.currentUser }
|
||||
}
|
||||
|
||||
this.currentUser = {
|
||||
id: userInfo.id,
|
||||
username: userInfo.username,
|
||||
userType: userInfo.userType
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the original Admin user before any user switch
|
||||
*/
|
||||
public getOriginalAdmin(): UserInfo | null {
|
||||
return this.originalAdminUser
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all users from database (for Admin user selection)
|
||||
*/
|
||||
public async getAllUsers(): Promise<UserInfo[]> {
|
||||
try {
|
||||
const { BIPUsersDAO } = await import('./bip-users-dao')
|
||||
const dao = new BIPUsersDAO()
|
||||
return await dao.getAllUsers()
|
||||
} catch (error) {
|
||||
console.error('[SessionManager] Get all users error:', error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user