fix: user stats

This commit is contained in:
Feng Yue
2025-08-13 22:34:22 +08:00
parent a3c9e39401
commit 2756671117
5 changed files with 235 additions and 165 deletions

View File

@@ -490,7 +490,9 @@ const authenticateUser = async (req, res, next) => {
// 检查用户是否被禁用 // 检查用户是否被禁用
if (!user.isActive) { if (!user.isActive) {
logger.security(`🔒 Disabled user login attempt: ${user.username} from ${req.ip || 'unknown'}`) logger.security(
`🔒 Disabled user login attempt: ${user.username} from ${req.ip || 'unknown'}`
)
return res.status(403).json({ return res.status(403).json({
error: 'Account disabled', error: 'Account disabled',
message: 'Your account has been disabled. Please contact administrator.' message: 'Your account has been disabled. Please contact administrator.'
@@ -506,7 +508,7 @@ const authenticateUser = async (req, res, next) => {
firstName: user.firstName, firstName: user.firstName,
lastName: user.lastName, lastName: user.lastName,
role: user.role, role: user.role,
sessionToken: sessionToken, sessionToken,
sessionCreatedAt: session.createdAt sessionCreatedAt: session.createdAt
} }
@@ -606,7 +608,6 @@ const authenticateUserOrAdmin = async (req, res, next) => {
error: 'Authentication required', error: 'Authentication required',
message: 'Please login as user or admin to access this resource' message: 'Please login as user or admin to access this resource'
}) })
} catch (error) { } catch (error) {
const authDuration = Date.now() - startTime const authDuration = Date.now() - startTime
logger.error(`❌ User/Admin authentication error (${authDuration}ms):`, { logger.error(`❌ User/Admin authentication error (${authDuration}ms):`, {
@@ -624,8 +625,7 @@ const authenticateUserOrAdmin = async (req, res, next) => {
} }
// 🛡️ 权限检查中间件 // 🛡️ 权限检查中间件
const requireRole = (allowedRoles) => { const requireRole = (allowedRoles) => (req, res, next) => {
return (req, res, next) => {
// 管理员始终有权限 // 管理员始终有权限
if (req.admin) { if (req.admin) {
return next() return next()
@@ -639,7 +639,9 @@ const requireRole = (allowedRoles) => {
if (allowed.includes(userRole)) { if (allowed.includes(userRole)) {
return next() return next()
} else { } else {
logger.security(`🚫 Access denied for user ${req.user.username} (role: ${userRole}) to ${req.originalUrl}`) logger.security(
`🚫 Access denied for user ${req.user.username} (role: ${userRole}) to ${req.originalUrl}`
)
return res.status(403).json({ return res.status(403).json({
error: 'Insufficient permissions', error: 'Insufficient permissions',
message: `This resource requires one of the following roles: ${allowed.join(', ')}` message: `This resource requires one of the following roles: ${allowed.join(', ')}`
@@ -651,7 +653,6 @@ const requireRole = (allowedRoles) => {
error: 'Authentication required', error: 'Authentication required',
message: 'Please login to access this resource' message: 'Please login to access this resource'
}) })
}
} }
// 🔒 管理员权限检查中间件 // 🔒 管理员权限检查中间件
@@ -665,7 +666,9 @@ const requireAdmin = (req, res, next) => {
return next() return next()
} }
logger.security(`🚫 Admin access denied for ${req.user?.username || 'unknown'} from ${req.ip || 'unknown'}`) logger.security(
`🚫 Admin access denied for ${req.user?.username || 'unknown'} from ${req.ip || 'unknown'}`
)
return res.status(403).json({ return res.status(403).json({
error: 'Admin access required', error: 'Admin access required',
message: 'This resource requires administrator privileges' message: 'This resource requires administrator privileges'

View File

@@ -66,7 +66,6 @@ router.post('/login', async (req, res) => {
}, },
sessionToken: authResult.sessionToken sessionToken: authResult.sessionToken
}) })
} catch (error) { } catch (error) {
logger.error('❌ User login error:', error) logger.error('❌ User login error:', error)
res.status(500).json({ res.status(500).json({
@@ -87,7 +86,6 @@ router.post('/logout', authenticateUser, async (req, res) => {
success: true, success: true,
message: 'Logout successful' message: 'Logout successful'
}) })
} catch (error) { } catch (error) {
logger.error('❌ User logout error:', error) logger.error('❌ User logout error:', error)
res.status(500).json({ res.status(500).json({
@@ -125,7 +123,6 @@ router.get('/profile', authenticateUser, async (req, res) => {
totalUsage: user.totalUsage totalUsage: user.totalUsage
} }
}) })
} catch (error) { } catch (error) {
logger.error('❌ Get user profile error:', error) logger.error('❌ Get user profile error:', error)
res.status(500).json({ res.status(500).json({
@@ -141,7 +138,7 @@ router.get('/api-keys', authenticateUser, async (req, res) => {
const apiKeys = await apiKeyService.getUserApiKeys(req.user.id) const apiKeys = await apiKeyService.getUserApiKeys(req.user.id)
// 移除敏感信息 // 移除敏感信息
const safeApiKeys = apiKeys.map(key => ({ const safeApiKeys = apiKeys.map((key) => ({
id: key.id, id: key.id,
name: key.name, name: key.name,
description: key.description, description: key.description,
@@ -154,7 +151,9 @@ router.get('/api-keys', authenticateUser, async (req, res) => {
dailyCost: key.dailyCost, dailyCost: key.dailyCost,
dailyCostLimit: key.dailyCostLimit, dailyCostLimit: key.dailyCostLimit,
// 不返回实际的key值只返回前缀和后几位 // 不返回实际的key值只返回前缀和后几位
keyPreview: key.key ? `${key.key.substring(0, 8)}...${key.key.substring(key.key.length - 4)}` : null keyPreview: key.key
? `${key.key.substring(0, 8)}...${key.key.substring(key.key.length - 4)}`
: null
})) }))
res.json({ res.json({
@@ -162,7 +161,6 @@ router.get('/api-keys', authenticateUser, async (req, res) => {
apiKeys: safeApiKeys, apiKeys: safeApiKeys,
total: safeApiKeys.length total: safeApiKeys.length
}) })
} catch (error) { } catch (error) {
logger.error('❌ Get user API keys error:', error) logger.error('❌ Get user API keys error:', error)
res.status(500).json({ res.status(500).json({
@@ -227,7 +225,6 @@ router.post('/api-keys', authenticateUser, async (req, res) => {
createdAt: newApiKey.createdAt createdAt: newApiKey.createdAt
} }
}) })
} catch (error) { } catch (error) {
logger.error('❌ Create user API key error:', error) logger.error('❌ Create user API key error:', error)
res.status(500).json({ res.status(500).json({
@@ -265,7 +262,6 @@ router.post('/api-keys/:keyId/regenerate', authenticateUser, async (req, res) =>
updatedAt: newKey.updatedAt updatedAt: newKey.updatedAt
} }
}) })
} catch (error) { } catch (error) {
logger.error('❌ Regenerate user API key error:', error) logger.error('❌ Regenerate user API key error:', error)
res.status(500).json({ res.status(500).json({
@@ -301,7 +297,6 @@ router.delete('/api-keys/:keyId', authenticateUser, async (req, res) => {
success: true, success: true,
message: 'API key deleted successfully' message: 'API key deleted successfully'
}) })
} catch (error) { } catch (error) {
logger.error('❌ Delete user API key error:', error) logger.error('❌ Delete user API key error:', error)
res.status(500).json({ res.status(500).json({
@@ -318,7 +313,7 @@ router.get('/usage-stats', authenticateUser, async (req, res) => {
// 获取用户的API Keys // 获取用户的API Keys
const userApiKeys = await apiKeyService.getUserApiKeys(req.user.id) const userApiKeys = await apiKeyService.getUserApiKeys(req.user.id)
const apiKeyIds = userApiKeys.map(key => key.id) const apiKeyIds = userApiKeys.map((key) => key.id)
if (apiKeyIds.length === 0) { if (apiKeyIds.length === 0) {
return res.json({ return res.json({
@@ -341,7 +336,6 @@ router.get('/usage-stats', authenticateUser, async (req, res) => {
success: true, success: true,
stats stats
}) })
} catch (error) { } catch (error) {
logger.error('❌ Get user usage stats error:', error) logger.error('❌ Get user usage stats error:', error)
res.status(500).json({ res.status(500).json({
@@ -371,7 +365,8 @@ router.get('/', authenticateUserOrAdmin, requireAdmin, async (req, res) => {
let filteredUsers = result.users let filteredUsers = result.users
if (search) { if (search) {
const searchLower = search.toLowerCase() const searchLower = search.toLowerCase()
filteredUsers = result.users.filter(user => filteredUsers = result.users.filter(
(user) =>
user.username.toLowerCase().includes(searchLower) || user.username.toLowerCase().includes(searchLower) ||
user.displayName.toLowerCase().includes(searchLower) || user.displayName.toLowerCase().includes(searchLower) ||
user.email.toLowerCase().includes(searchLower) user.email.toLowerCase().includes(searchLower)
@@ -388,7 +383,6 @@ router.get('/', authenticateUserOrAdmin, requireAdmin, async (req, res) => {
totalPages: result.totalPages totalPages: result.totalPages
} }
}) })
} catch (error) { } catch (error) {
logger.error('❌ Get users list error:', error) logger.error('❌ Get users list error:', error)
res.status(500).json({ res.status(500).json({
@@ -418,7 +412,7 @@ router.get('/:userId', authenticateUserOrAdmin, requireAdmin, async (req, res) =
success: true, success: true,
user: { user: {
...user, ...user,
apiKeys: apiKeys.map(key => ({ apiKeys: apiKeys.map((key) => ({
id: key.id, id: key.id,
name: key.name, name: key.name,
description: key.description, description: key.description,
@@ -426,11 +420,12 @@ router.get('/:userId', authenticateUserOrAdmin, requireAdmin, async (req, res) =
createdAt: key.createdAt, createdAt: key.createdAt,
lastUsedAt: key.lastUsedAt, lastUsedAt: key.lastUsedAt,
usage: key.usage, usage: key.usage,
keyPreview: key.key ? `${key.key.substring(0, 8)}...${key.key.substring(key.key.length - 4)}` : null keyPreview: key.key
? `${key.key.substring(0, 8)}...${key.key.substring(key.key.length - 4)}`
: null
})) }))
} }
}) })
} catch (error) { } catch (error) {
logger.error('❌ Get user details error:', error) logger.error('❌ Get user details error:', error)
res.status(500).json({ res.status(500).json({
@@ -456,7 +451,9 @@ router.patch('/:userId/status', authenticateUserOrAdmin, requireAdmin, async (re
const updatedUser = await userService.updateUserStatus(userId, isActive) const updatedUser = await userService.updateUserStatus(userId, isActive)
const adminUser = req.admin?.username || req.user?.username const adminUser = req.admin?.username || req.user?.username
logger.info(`🔄 Admin ${adminUser} ${isActive ? 'enabled' : 'disabled'} user: ${updatedUser.username}`) logger.info(
`🔄 Admin ${adminUser} ${isActive ? 'enabled' : 'disabled'} user: ${updatedUser.username}`
)
res.json({ res.json({
success: true, success: true,
@@ -468,7 +465,6 @@ router.patch('/:userId/status', authenticateUserOrAdmin, requireAdmin, async (re
updatedAt: updatedUser.updatedAt updatedAt: updatedUser.updatedAt
} }
}) })
} catch (error) { } catch (error) {
logger.error('❌ Update user status error:', error) logger.error('❌ Update user status error:', error)
res.status(500).json({ res.status(500).json({
@@ -507,7 +503,6 @@ router.patch('/:userId/role', authenticateUserOrAdmin, requireAdmin, async (req,
updatedAt: updatedUser.updatedAt updatedAt: updatedUser.updatedAt
} }
}) })
} catch (error) { } catch (error) {
logger.error('❌ Update user role error:', error) logger.error('❌ Update user role error:', error)
res.status(500).json({ res.status(500).json({
@@ -540,7 +535,6 @@ router.post('/:userId/disable-keys', authenticateUserOrAdmin, requireAdmin, asyn
message: `Disabled ${result.count} API keys for user ${user.username}`, message: `Disabled ${result.count} API keys for user ${user.username}`,
disabledCount: result.count disabledCount: result.count
}) })
} catch (error) { } catch (error) {
logger.error('❌ Disable user API keys error:', error) logger.error('❌ Disable user API keys error:', error)
res.status(500).json({ res.status(500).json({
@@ -566,7 +560,7 @@ router.get('/:userId/usage-stats', authenticateUserOrAdmin, requireAdmin, async
// 获取用户的API Keys // 获取用户的API Keys
const userApiKeys = await apiKeyService.getUserApiKeys(userId) const userApiKeys = await apiKeyService.getUserApiKeys(userId)
const apiKeyIds = userApiKeys.map(key => key.id) const apiKeyIds = userApiKeys.map((key) => key.id)
if (apiKeyIds.length === 0) { if (apiKeyIds.length === 0) {
return res.json({ return res.json({
@@ -599,7 +593,6 @@ router.get('/:userId/usage-stats', authenticateUserOrAdmin, requireAdmin, async
}, },
stats stats
}) })
} catch (error) { } catch (error) {
logger.error('❌ Get user usage stats (admin) error:', error) logger.error('❌ Get user usage stats (admin) error:', error)
res.status(500).json({ res.status(500).json({
@@ -618,7 +611,6 @@ router.get('/stats/overview', authenticateUserOrAdmin, requireAdmin, async (req,
success: true, success: true,
stats stats
}) })
} catch (error) { } catch (error) {
logger.error('❌ Get user stats overview error:', error) logger.error('❌ Get user stats overview error:', error)
res.status(500).json({ res.status(500).json({
@@ -638,7 +630,6 @@ router.get('/admin/ldap-test', authenticateUserOrAdmin, requireAdmin, async (req
ldapTest: testResult, ldapTest: testResult,
config: ldapService.getConfigInfo() config: ldapService.getConfigInfo()
}) })
} catch (error) { } catch (error) {
logger.error('❌ LDAP test error:', error) logger.error('❌ LDAP test error:', error)
res.status(500).json({ res.status(500).json({

View File

@@ -492,8 +492,8 @@ class ApiKeyService {
try { try {
const allKeys = await redis.getAllApiKeys() const allKeys = await redis.getAllApiKeys()
return allKeys return allKeys
.filter(key => key.userId === userId) .filter((key) => key.userId === userId)
.map(key => ({ .map((key) => ({
id: key.id, id: key.id,
name: key.name, name: key.name,
description: key.description, description: key.description,
@@ -520,7 +520,9 @@ class ApiKeyService {
async getApiKeyById(keyId, userId = null) { async getApiKeyById(keyId, userId = null) {
try { try {
const keyData = await redis.getApiKey(keyId) const keyData = await redis.getApiKey(keyId)
if (!keyData) return null if (!keyData) {
return null
}
// 如果指定了用户ID检查权限 // 如果指定了用户ID检查权限
if (userId && keyData.userId !== userId) { if (userId && keyData.userId !== userId) {

View File

@@ -29,7 +29,10 @@ class LdapService {
errors.push('LDAP bind DN is not configured or invalid') errors.push('LDAP bind DN is not configured or invalid')
} }
if (!this.config.server.bindCredentials || typeof this.config.server.bindCredentials !== 'string') { if (
!this.config.server.bindCredentials ||
typeof this.config.server.bindCredentials !== 'string'
) {
errors.push('LDAP bind credentials are not configured or invalid') errors.push('LDAP bind credentials are not configured or invalid')
} }
@@ -184,8 +187,8 @@ class LdapService {
async bindClient(client) { async bindClient(client) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 验证绑定凭据 // 验证绑定凭据
const bindDN = this.config.server.bindDN const { bindDN } = this.config.server
const bindCredentials = this.config.server.bindCredentials const { bindCredentials } = this.config.server
if (!bindDN || typeof bindDN !== 'string') { if (!bindDN || typeof bindDN !== 'string') {
const error = new Error('LDAP bind DN is not configured or invalid') const error = new Error('LDAP bind DN is not configured or invalid')
@@ -256,7 +259,9 @@ class LdapService {
}) })
res.on('end', (result) => { res.on('end', (result) => {
logger.debug(`✅ LDAP search completed. Status: ${result.status}, Found ${entries.length} entries`) logger.debug(
`✅ LDAP search completed. Status: ${result.status}, Found ${entries.length} entries`
)
if (entries.length === 0) { if (entries.length === 0) {
resolve(null) resolve(null)
@@ -329,7 +334,7 @@ class LdapService {
// 创建属性映射 // 创建属性映射
const attrMap = {} const attrMap = {}
attributes.forEach(attr => { attributes.forEach((attr) => {
const name = attr.type || attr.name const name = attr.type || attr.name
const values = Array.isArray(attr.values) ? attr.values : [attr.values] const values = Array.isArray(attr.values) ? attr.values : [attr.values]
attrMap[name] = values.length === 1 ? values[0] : values attrMap[name] = values.length === 1 ? values[0] : values
@@ -386,7 +391,10 @@ class LdapService {
throw new Error('LDAP bind DN is not configured') throw new Error('LDAP bind DN is not configured')
} }
if (!this.config.server.bindCredentials || typeof this.config.server.bindCredentials !== 'string') { if (
!this.config.server.bindCredentials ||
typeof this.config.server.bindCredentials !== 'string'
) {
throw new Error('LDAP bind credentials are not configured') throw new Error('LDAP bind credentials are not configured')
} }
@@ -470,7 +478,6 @@ class LdapService {
sessionToken, sessionToken,
message: 'Authentication successful' message: 'Authentication successful'
} }
} catch (error) { } catch (error) {
logger.error('❌ LDAP authentication error:', error) logger.error('❌ LDAP authentication error:', error)
return { return {

View File

@@ -1,6 +1,5 @@
const redis = require('../models/redis') const redis = require('../models/redis')
const crypto = require('crypto') const crypto = require('crypto')
const bcrypt = require('bcryptjs')
const logger = require('../utils/logger') const logger = require('../utils/logger')
const config = require('../../config/config') const config = require('../../config/config')
@@ -88,7 +87,9 @@ class UserService {
async getUserByUsername(username) { async getUserByUsername(username) {
try { try {
const userId = await redis.get(`${this.usernamePrefix}${username}`) const userId = await redis.get(`${this.usernamePrefix}${username}`)
if (!userId) return null if (!userId) {
return null
}
const userData = await redis.get(`${this.userPrefix}${userId}`) const userData = await redis.get(`${this.userPrefix}${userId}`)
return userData ? JSON.parse(userData) : null return userData ? JSON.parse(userData) : null
@@ -99,16 +100,100 @@ class UserService {
} }
// 👤 通过ID获取用户 // 👤 通过ID获取用户
async getUserById(userId) { async getUserById(userId, calculateUsage = true) {
try { try {
const userData = await redis.get(`${this.userPrefix}${userId}`) const userData = await redis.get(`${this.userPrefix}${userId}`)
return userData ? JSON.parse(userData) : null if (!userData) {
return null
}
const user = JSON.parse(userData)
// Calculate totalUsage by aggregating user's API keys usage (if requested)
if (calculateUsage) {
try {
const usageStats = await this.calculateUserUsageStats(userId)
user.totalUsage = usageStats.totalUsage
user.apiKeyCount = usageStats.apiKeyCount
} catch (error) {
logger.error('❌ Error calculating user usage stats:', error)
// Fallback to stored values if calculation fails
user.totalUsage = user.totalUsage || {
requests: 0,
inputTokens: 0,
outputTokens: 0,
totalCost: 0
}
user.apiKeyCount = user.apiKeyCount || 0
}
}
return user
} catch (error) { } catch (error) {
logger.error('❌ Error getting user by ID:', error) logger.error('❌ Error getting user by ID:', error)
throw error throw error
} }
} }
// 📊 计算用户使用统计通过聚合API Keys
async calculateUserUsageStats(userId) {
try {
// Use redis directly to avoid circular dependency
const client = redis.getClientSafe()
const pattern = 'api_key:*'
const keys = await client.keys(pattern)
const userApiKeys = []
for (const key of keys) {
const keyData = await client.get(key)
if (keyData) {
const apiKey = JSON.parse(keyData)
if (apiKey.userId === userId) {
// Get usage stats for this API key
const usage = await redis.getUsageStats(apiKey.id)
userApiKeys.push({
id: apiKey.id,
name: apiKey.name,
usage
})
}
}
}
const totalUsage = {
requests: 0,
inputTokens: 0,
outputTokens: 0,
totalCost: 0
}
for (const apiKey of userApiKeys) {
if (apiKey.usage) {
totalUsage.requests += apiKey.usage.requests || 0
totalUsage.inputTokens += apiKey.usage.inputTokens || 0
totalUsage.outputTokens += apiKey.usage.outputTokens || 0
totalUsage.totalCost += apiKey.usage.totalCost || 0
}
}
return {
totalUsage,
apiKeyCount: userApiKeys.length
}
} catch (error) {
logger.error('❌ Error calculating user usage stats:', error)
return {
totalUsage: {
requests: 0,
inputTokens: 0,
outputTokens: 0,
totalCost: 0
},
apiKeyCount: 0
}
}
}
// 📋 获取所有用户列表(管理员功能) // 📋 获取所有用户列表(管理员功能)
async getAllUsers(options = {}) { async getAllUsers(options = {}) {
try { try {
@@ -124,8 +209,12 @@ class UserService {
const user = JSON.parse(userData) const user = JSON.parse(userData)
// 应用过滤条件 // 应用过滤条件
if (role && user.role !== role) continue if (role && user.role !== role) {
if (typeof isActive === 'boolean' && user.isActive !== isActive) continue continue
}
if (typeof isActive === 'boolean' && user.isActive !== isActive) {
continue
}
users.push(user) users.push(user)
} }
@@ -153,7 +242,7 @@ class UserService {
// 🔄 更新用户状态 // 🔄 更新用户状态
async updateUserStatus(userId, isActive) { async updateUserStatus(userId, isActive) {
try { try {
const user = await this.getUserById(userId) const user = await this.getUserById(userId, false) // Skip usage calculation
if (!user) { if (!user) {
throw new Error('User not found') throw new Error('User not found')
} }
@@ -179,7 +268,7 @@ class UserService {
// 🔄 更新用户角色 // 🔄 更新用户角色
async updateUserRole(userId, role) { async updateUserRole(userId, role) {
try { try {
const user = await this.getUserById(userId) const user = await this.getUserById(userId, false) // Skip usage calculation
if (!user) { if (!user) {
throw new Error('User not found') throw new Error('User not found')
} }
@@ -197,46 +286,22 @@ class UserService {
} }
} }
// 📊 更新用户使用统计 // 📊 更新用户API Key数量 (已废弃,现在通过聚合计算)
async updateUserUsage(userId, usage) { async updateUserApiKeyCount(userId, _count) {
try { // This method is deprecated since apiKeyCount is now calculated dynamically
const user = await this.getUserById(userId) // in getUserById by aggregating the user's API keys
if (!user) return logger.debug(
`📊 updateUserApiKeyCount called for ${userId} but is now deprecated (count auto-calculated)`
const { requests = 0, inputTokens = 0, outputTokens = 0, cost = 0 } = usage )
user.totalUsage.requests += requests
user.totalUsage.inputTokens += inputTokens
user.totalUsage.outputTokens += outputTokens
user.totalUsage.totalCost += cost
user.updatedAt = new Date().toISOString()
await redis.set(`${this.userPrefix}${userId}`, JSON.stringify(user))
} catch (error) {
logger.error('❌ Error updating user usage:', error)
}
}
// 📊 更新用户API Key数量
async updateUserApiKeyCount(userId, count) {
try {
const user = await this.getUserById(userId)
if (!user) return
user.apiKeyCount = count
user.updatedAt = new Date().toISOString()
await redis.set(`${this.userPrefix}${userId}`, JSON.stringify(user))
} catch (error) {
logger.error('❌ Error updating user API key count:', error)
}
} }
// 📝 记录用户登录 // 📝 记录用户登录
async recordUserLogin(userId) { async recordUserLogin(userId) {
try { try {
const user = await this.getUserById(userId) const user = await this.getUserById(userId, false) // Skip usage calculation
if (!user) return if (!user) {
return
}
user.lastLoginAt = new Date().toISOString() user.lastLoginAt = new Date().toISOString()
await redis.set(`${this.userPrefix}${userId}`, JSON.stringify(user)) await redis.set(`${this.userPrefix}${userId}`, JSON.stringify(user))
@@ -272,7 +337,9 @@ class UserService {
async validateUserSession(sessionToken) { async validateUserSession(sessionToken) {
try { try {
const sessionData = await redis.get(`${this.userSessionPrefix}${sessionToken}`) const sessionData = await redis.get(`${this.userSessionPrefix}${sessionToken}`)
if (!sessionData) return null if (!sessionData) {
return null
}
const session = JSON.parse(sessionData) const session = JSON.parse(sessionData)
@@ -283,7 +350,7 @@ class UserService {
} }
// 获取用户信息 // 获取用户信息
const user = await this.getUserById(session.userId) const user = await this.getUserById(session.userId, false) // Skip usage calculation for validation
if (!user || !user.isActive) { if (!user || !user.isActive) {
await this.invalidateUserSession(sessionToken) await this.invalidateUserSession(sessionToken)
return null return null
@@ -332,7 +399,7 @@ class UserService {
// 🗑️ 删除用户(软删除,标记为不活跃) // 🗑️ 删除用户(软删除,标记为不活跃)
async deleteUser(userId) { async deleteUser(userId) {
try { try {
const user = await this.getUserById(userId) const user = await this.getUserById(userId, false) // Skip usage calculation
if (!user) { if (!user) {
throw new Error('User not found') throw new Error('User not found')
} }