debug: 添加详细的登录调试日志

- 在后端login控制器中添加详细的执行步骤日志
- 添加错误捕获和处理,防止未捕获的异常
- 在前端LoginForm中添加详细的错误日志输出
- 在rate limiter中添加详细的限制日志
- 在请求日志中添加POST请求体信息
- 帮助定位401错误的具体原因

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-09-06 09:57:59 +08:00
parent f583f787f0
commit 19a8426163
3 changed files with 40 additions and 2 deletions

View File

@@ -103,13 +103,18 @@ export const authController = {
// 用户登录
async login(req: Request, res: Response) {
try {
const { username, password } = req.body;
console.log('登录请求:', { username, timestamp: new Date().toISOString() });
// Find user
const user = await prisma.user.findUnique({
where: { username }
});
console.log('查找用户结果:', { found: !!user, isActive: user?.isActive, userId: user?.id });
if (!user) {
// 记录登录失败审计日志
await prisma.auditLog.create({
@@ -144,7 +149,10 @@ export const authController = {
}
// Verify password
console.log('开始验证密码...');
const isValidPassword = await bcrypt.compare(password, user.password);
console.log('密码验证结果:', { isValid: isValidPassword });
if (!isValidPassword) {
// 增加登录失败次数
const loginAttempts = (user.loginAttempts || 0) + 1;
@@ -199,17 +207,22 @@ export const authController = {
});
// Generate token
console.log('生成token...');
const token = generateToken(user.id);
console.log('Token生成成功:', token.substring(0, 20) + '...');
// Delete existing sessions for this user (optional - for single session per user)
console.log('删除用户现有sessions...');
await prisma.session.deleteMany({
where: { userId: user.id }
});
// Create session
console.log('创建新session...');
await createSession(user.id, token, req);
// Update last login
console.log('更新最后登录时间...');
await prisma.user.update({
where: { id: user.id },
data: { lastLoginAt: new Date() }
@@ -227,6 +240,7 @@ export const authController = {
}
});
console.log('登录成功,返回响应...');
return res.json({
message: '登录成功',
token,
@@ -236,6 +250,10 @@ export const authController = {
isAdmin: user.isAdmin,
}
});
} catch (error) {
console.error('登录过程中发生错误:', error);
return res.status(500).json({ error: '服务器内部错误' });
}
},
// 用户登出

View File

@@ -37,6 +37,13 @@ const limiter = rateLimit({
max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS || '100'), // limit each IP to 100 requests per windowMs
message: {
error: 'Too many requests from this IP, please try again later.'
},
// 添加详细日志
handler: (req, res) => {
console.log('Rate limit exceeded for IP:', req.ip, 'Path:', req.path);
res.status(429).json({
error: 'Too many requests from this IP, please try again later.'
});
}
});
app.use('/api/', limiter);
@@ -47,6 +54,12 @@ app.use(express.urlencoded({ extended: true }));
// Request logging
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`, {
ip: (req.headers['x-forwarded-for'] as string) || req.socket.remoteAddress,
userAgent: req.get('User-Agent'),
body: req.method === 'POST' ? req.body : undefined
});
logger.info(`${req.method} ${req.path}`, {
ip: (req.headers['x-forwarded-for'] as string) || req.socket.remoteAddress,
userAgent: req.get('User-Agent')

View File

@@ -116,7 +116,14 @@ const handleLogin = async () => {
router.push('/dashboard')
} catch (error: any) {
console.log(error)
console.error('登录失败,详细错误信息:', {
status: error.response?.status,
statusText: error.response?.statusText,
data: error.response?.data,
url: error.config?.url,
method: error.config?.method,
headers: error.config?.headers
})
// 根据不同的错误类型显示不同的错误信息
if (error.response?.status === 401) {
const errorMessage = error.response?.data?.error || '用户名或密码错误'