feat(logging-p0): complete Wave 2 - Auth/Extractor/Cleaner services transformed

This commit is contained in:
Misaka
2026-04-04 10:39:06 +08:00
parent 24d9bfebaf
commit 78a3066904
14 changed files with 3183 additions and 416 deletions

View File

@@ -1,7 +1,7 @@
import { hostname } from 'os'
import { SessionManager } from '../user/session-manager'
import { UpdateService } from '../update/update-service'
import { createLogger } from '../logger'
import { createLogger, run, getRequestId, getContext } from '../logger'
import { logAudit } from '../logger/audit-logger'
import { ValidationError } from '../../types/errors'
import type { UserInfo } from '../../types/user.types'
@@ -23,120 +23,212 @@ export class AuthApplicationService {
) {}
async getComputerName(): Promise<string> {
const requestId = getRequestId()
if (requestId) {
log.debug('Get computer name', { requestId })
}
return hostname()
}
async silentLogin(): Promise<SilentLoginResponse> {
if (this.silentLoginPromise) {
log.debug('Reusing in-flight silent login request')
log.debug('Reusing in-flight silent login request', { requestId: getRequestId() })
return this.silentLoginPromise
}
this.silentLoginPromise = this.performSilentLogin()
try {
return await this.silentLoginPromise
} finally {
this.silentLoginPromise = null
}
}
this.silentLoginPromise = run(
async (): Promise<SilentLoginResponse> => {
const requestId = getRequestId()
const context = getContext()
const startTime = performance.now()
private async performSilentLogin(): Promise<SilentLoginResponse> {
log.info('Attempting silent login')
const success = await this.sessionManager.loginByComputerName()
const userInfo = this.sessionManager.getUserInfo()
try {
log.info('Attempting silent login', { requestId, operation: context?.operation })
const success = await this.sessionManager.loginByComputerName()
const userInfo = this.sessionManager.getUserInfo()
if (!success || !userInfo) {
await this.updateService.setUserContext(null)
throw new ValidationError('无感登录失败:未找到匹配用户', 'VAL_INVALID_INPUT')
}
if (!success || !userInfo) {
await this.updateService.setUserContext(null)
const error = new ValidationError('无感登录失败:未找到匹配用户', 'VAL_INVALID_INPUT')
log.error('Silent login failed - user not found', {
operation: 'silentLogin',
requestId,
userId: userInfo?.id,
username: userInfo?.username,
computerName: hostname(),
error
})
throw error
}
await this.updateService.setUserContext(userInfo.userType)
await this.updateService.setUserContext(userInfo.userType)
const requiresUserSelection = userInfo.userType === 'Admin'
log.info('Silent login successful', {
username: userInfo.username,
userType: userInfo.userType,
requiresUserSelection
})
const requiresUserSelection = userInfo.userType === 'Admin'
log.info('Silent login successful', {
requestId,
operation: context?.operation,
username: userInfo.username,
userType: userInfo.userType,
requiresUserSelection,
userId: userInfo.id
})
this.writeAuditLog('LOGIN', String(userInfo.id), {
username: userInfo.username,
computerName: hostname(),
resource: 'ERP_SYSTEM',
status: 'success',
metadata: { loginType: 'silent', userType: userInfo.userType }
})
this.writeAuditLog('LOGIN', String(userInfo.id), {
username: userInfo.username,
computerName: hostname(),
resource: 'ERP_SYSTEM',
status: 'success',
metadata: { loginType: 'silent', userType: userInfo.userType }
})
return {
success: true,
userInfo,
requiresUserSelection
}
return {
success: true,
userInfo,
requiresUserSelection
}
} finally {
const durationMs = performance.now() - startTime
if (durationMs > 1000) {
log.warn(`Silent login took ${durationMs.toFixed(2)}ms (SLOW)`, {
operation: 'silentLogin',
requestId,
durationMs
})
} else {
log.debug(`Silent login completed in ${durationMs.toFixed(2)}ms`, {
operation: 'silentLogin',
requestId,
durationMs
})
}
}
},
{ operation: 'silentLogin' }
)
return this.silentLoginPromise
}
async login(username: string, password: string): Promise<LoginResponse> {
if (!username || !password) {
log.warn('Login attempt with missing credentials')
log.warn('Login attempt with missing credentials', { requestId: getRequestId() })
throw new ValidationError('请输入用户名和密码', 'VAL_MISSING_REQUIRED')
}
log.info('Login attempt', { username })
const success = await this.sessionManager.login(username, password)
const userInfo = this.sessionManager.getUserInfo()
return run(
async (): Promise<LoginResponse> => {
const requestId = getRequestId()
const context = getContext()
if (!success || !userInfo) {
this.writeAuditLog('LOGIN', '0', {
username,
computerName: hostname(),
resource: 'ERP_SYSTEM',
status: 'failure',
metadata: { loginType: 'credentials', reason: 'invalid_credentials' }
})
const startTime = performance.now()
log.warn('Login failed - invalid credentials', { username })
await this.updateService.setUserContext(null)
throw new ValidationError('用户名或密码错误', 'VAL_INVALID_INPUT')
}
try {
log.info('Login attempt', { username, requestId, operation: context?.operation })
const success = await this.sessionManager.login(username, password)
const userInfo = this.sessionManager.getUserInfo()
log.info('Login successful', { username, userType: userInfo.userType })
await this.updateService.setUserContext(userInfo.userType)
if (!success || !userInfo) {
this.writeAuditLog('LOGIN', '0', {
username,
computerName: hostname(),
resource: 'ERP_SYSTEM',
status: 'failure',
metadata: { loginType: 'credentials', reason: 'invalid_credentials' }
})
this.writeAuditLog('LOGIN', String(userInfo.id), {
username: userInfo.username,
computerName: hostname(),
resource: 'ERP_SYSTEM',
status: 'success',
metadata: { loginType: 'credentials', userType: userInfo.userType }
})
const error = new ValidationError('用户名或密码错误', 'VAL_INVALID_INPUT')
log.warn('Login failed - invalid credentials', {
username,
requestId,
operation: context?.operation,
error
})
await this.updateService.setUserContext(null)
throw error
}
return {
success: true,
userInfo
}
log.info('Login successful', {
requestId,
operation: context?.operation,
username,
userType: userInfo.userType,
userId: userInfo.id
})
await this.updateService.setUserContext(userInfo.userType)
this.writeAuditLog('LOGIN', String(userInfo.id), {
username: userInfo.username,
computerName: hostname(),
resource: 'ERP_SYSTEM',
status: 'success',
metadata: { loginType: 'credentials', userType: userInfo.userType }
})
return {
success: true,
userInfo
}
} finally {
const durationMs = performance.now() - startTime
if (durationMs > 1000) {
log.warn(`Login took ${durationMs.toFixed(2)}ms (SLOW)`, {
operation: 'login',
requestId,
durationMs,
username
})
} else {
log.debug(`Login completed in ${durationMs.toFixed(2)}ms`, {
operation: 'login',
requestId,
durationMs
})
}
}
},
{ operation: 'login' }
)
}
async logout(): Promise<void> {
const userInfo = this.sessionManager.getUserInfo()
log.info('User logout', { username: userInfo?.username })
return run(
async () => {
const requestId = getRequestId()
const context = getContext()
const userInfo = this.sessionManager.getUserInfo()
if (userInfo) {
this.writeAuditLog('LOGOUT', String(userInfo.id), {
username: userInfo.username,
computerName: hostname(),
resource: 'ERP_SYSTEM',
status: 'success',
metadata: { userType: userInfo.userType }
})
}
log.info('User logout', {
requestId,
operation: context?.operation,
username: userInfo?.username,
userId: userInfo?.id
})
this.sessionManager.logout()
await this.updateService.setUserContext(null)
if (userInfo) {
this.writeAuditLog('LOGOUT', String(userInfo.id), {
username: userInfo.username,
computerName: hostname(),
resource: 'ERP_SYSTEM',
status: 'success',
metadata: { userType: userInfo.userType }
})
}
this.sessionManager.logout()
await this.updateService.setUserContext(null)
},
{ operation: 'logout' }
)
}
getCurrentUser(): CurrentUserResponse {
const requestId = getRequestId()
const isAuthenticated = this.sessionManager.isAuthenticated()
const userInfo = this.sessionManager.getUserInfo()
if (requestId) {
log.debug('Get current user', { requestId, isAuthenticated, userId: userInfo?.id })
}
return {
isAuthenticated,
userInfo: userInfo ?? undefined
@@ -144,27 +236,73 @@ export class AuthApplicationService {
}
async getAllUsers(): Promise<UserInfo[]> {
log.debug('Fetching all users for admin selection')
const requestId = getRequestId()
log.debug('Fetching all users for admin selection', { requestId })
return this.sessionManager.getAllUsers()
}
async switchUser(userInfo: UserInfo): Promise<UserSelectionResponse> {
log.info('User switch attempt', { targetUser: userInfo.username })
const success = this.sessionManager.switchUser(userInfo)
return run(
async (): Promise<UserSelectionResponse> => {
const requestId = getRequestId()
const context = getContext()
const startTime = performance.now()
if (!success) {
log.warn('User switch failed')
throw new ValidationError('用户切换失败', 'VAL_INVALID_INPUT')
}
try {
log.info('User switch attempt', {
requestId,
operation: context?.operation,
targetUser: userInfo.username,
targetUserId: userInfo.id
})
const success = this.sessionManager.switchUser(userInfo)
const newUser = this.sessionManager.getUserInfo()
log.info('User switch successful', { newUsername: newUser?.username })
await this.updateService.setUserContext(newUser?.userType ?? null)
if (!success) {
const error = new ValidationError('用户切换失败', 'VAL_INVALID_INPUT')
log.warn('User switch failed', {
requestId,
operation: context?.operation,
targetUser: userInfo.username,
targetUserId: userInfo.id,
error
})
throw error
}
return {
success: true,
userInfo: newUser ?? undefined
}
const newUser = this.sessionManager.getUserInfo()
log.info('User switch successful', {
requestId,
operation: context?.operation,
newUsername: newUser?.username,
newUserId: newUser?.id,
newUserType: newUser?.userType
})
await this.updateService.setUserContext(newUser?.userType ?? null)
return {
success: true,
userInfo: newUser ?? undefined
}
} finally {
const durationMs = performance.now() - startTime
if (durationMs > 1000) {
log.warn(`User switch took ${durationMs.toFixed(2)}ms (SLOW)`, {
operation: 'switchUser',
requestId,
durationMs,
targetUser: userInfo.username
})
} else {
log.debug(`User switch completed in ${durationMs.toFixed(2)}ms`, {
operation: 'switchUser',
requestId,
durationMs
})
}
}
},
{ operation: 'switchUser', userId: String(userInfo.id) }
)
}
isAdmin(): boolean {