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:
Misaka
2026-03-01 17:46:15 +08:00
parent 450eb41f96
commit 829851e3ca
12 changed files with 1671 additions and 112 deletions

View 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 []
}
}
}