登录增加fail2ban机制

This commit is contained in:
mtvpls
2026-05-18 11:19:44 +08:00
parent 464edee324
commit 2cabf76c2d
2 changed files with 204 additions and 0 deletions
+29
View File
@@ -4,6 +4,12 @@ import { NextRequest, NextResponse } from 'next/server';
import { parseAuthInfo } from '@/lib/auth';
import { getConfig } from '@/lib/config';
import { db } from '@/lib/db';
import {
checkLoginBan,
getLoginClientIp,
recordLoginFailure,
recordLoginSuccess,
} from '@/lib/login-fail2ban';
import {
generateRefreshToken,
generateTokenId,
@@ -177,6 +183,20 @@ function getDeviceInfo(request: NextRequest): string {
export async function POST(req: NextRequest) {
try {
const clientIp = getLoginClientIp(req);
const banStatus = checkLoginBan(clientIp);
if (banStatus.banned) {
return NextResponse.json(
{ error: '登录失败次数过多,请稍后再试' },
{
status: 429,
headers: banStatus.retryAfterSeconds
? { 'Retry-After': String(banStatus.retryAfterSeconds) }
: undefined,
}
);
}
// 获取站点配置
const adminConfig = await getConfig();
const siteConfig = adminConfig.SiteConfig;
@@ -206,12 +226,15 @@ export async function POST(req: NextRequest) {
}
if (password !== envPassword) {
recordLoginFailure(clientIp);
return NextResponse.json(
{ ok: false, error: '密码错误' },
{ status: 401 }
);
}
recordLoginSuccess(clientIp);
// 验证成功,设置认证cookie
const username = process.env.USERNAME || 'default';
const deviceInfo = getDeviceInfo(req);
@@ -279,6 +302,8 @@ export async function POST(req: NextRequest) {
username === process.env.USERNAME &&
password === process.env.PASSWORD
) {
recordLoginSuccess(clientIp);
// 验证成功,设置认证cookie
const deviceInfo = getDeviceInfo(req);
const cookieValue = await generateAuthCookie(
@@ -302,6 +327,7 @@ export async function POST(req: NextRequest) {
return response;
} else if (username === process.env.USERNAME) {
recordLoginFailure(clientIp);
return NextResponse.json({ error: '用户名或密码错误' }, { status: 401 });
}
@@ -326,12 +352,15 @@ export async function POST(req: NextRequest) {
}
if (!pass) {
recordLoginFailure(clientIp);
return NextResponse.json(
{ error: '用户名或密码错误' },
{ status: 401 }
);
}
recordLoginSuccess(clientIp);
// 验证成功,设置认证cookie
const deviceInfo = getDeviceInfo(req);
const cookieValue = await generateAuthCookie(