- 实现 JWT Token 生成和验证 - 实现登录、注册、登出、重置密码 API - 实现邮箱验证码发送功能(配置从环境变量读取) - 实现密码加密和验证工具 - 支持获取当前用户信息
128 lines
3.4 KiB
TypeScript
128 lines
3.4 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
||
import { z } from 'zod';
|
||
import { db } from '@/drizzle/db';
|
||
import { users, verificationCodes } from '@/drizzle/schema';
|
||
import { eq, and, gt } from 'drizzle-orm';
|
||
import { sendVerificationEmail, generateVerificationCode } from '@/lib/email';
|
||
import { validateEmail } from '@/lib/password';
|
||
|
||
// 请求体验证
|
||
const sendCodeSchema = z.object({
|
||
email: z.string().email('邮箱格式不正确'),
|
||
type: z.enum(['register', 'login', 'reset']),
|
||
});
|
||
|
||
export async function POST(request: NextRequest) {
|
||
try {
|
||
const body = await request.json();
|
||
|
||
// 验证请求体
|
||
const result = sendCodeSchema.safeParse(body);
|
||
if (!result.success) {
|
||
return NextResponse.json(
|
||
{ success: false, error: result.error.issues[0].message },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
const { email, type } = result.data;
|
||
|
||
// 验证邮箱格式
|
||
if (!validateEmail(email)) {
|
||
return NextResponse.json(
|
||
{ success: false, error: '邮箱格式不正确' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// 检查邮箱是否已注册(仅注册时检查)
|
||
if (type === 'register') {
|
||
const existingUser = await db
|
||
.select()
|
||
.from(users)
|
||
.where(eq(users.email, email))
|
||
.limit(1);
|
||
|
||
if (existingUser.length > 0) {
|
||
return NextResponse.json(
|
||
{ success: false, error: '该邮箱已被注册' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
}
|
||
|
||
// 检查邮箱是否存在(登录和重置密码时检查)
|
||
if (type === 'login' || type === 'reset') {
|
||
const existingUser = await db
|
||
.select()
|
||
.from(users)
|
||
.where(eq(users.email, email))
|
||
.limit(1);
|
||
|
||
if (existingUser.length === 0) {
|
||
return NextResponse.json(
|
||
{ success: false, error: '该邮箱未注册' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
}
|
||
|
||
// 检查是否频繁发送(1分钟内只能发送1次)
|
||
const oneMinuteAgo = new Date(Date.now() - 60 * 1000);
|
||
const recentCode = await db
|
||
.select()
|
||
.from(verificationCodes)
|
||
.where(
|
||
and(
|
||
eq(verificationCodes.email, email),
|
||
eq(verificationCodes.type, type),
|
||
gt(verificationCodes.createdAt, oneMinuteAgo)
|
||
)
|
||
)
|
||
.limit(1);
|
||
|
||
if (recentCode.length > 0) {
|
||
return NextResponse.json(
|
||
{ success: false, error: '发送太频繁,请稍后再试' },
|
||
{ status: 429 }
|
||
);
|
||
}
|
||
|
||
// 生成验证码
|
||
const code = generateVerificationCode();
|
||
|
||
// 计算过期时间(5分钟后)
|
||
const expiresAt = new Date(Date.now() + 5 * 60 * 1000);
|
||
|
||
// 保存验证码到数据库
|
||
await db.insert(verificationCodes).values({
|
||
email,
|
||
code,
|
||
type,
|
||
expiresAt,
|
||
});
|
||
|
||
// 发送邮件
|
||
const emailResult = await sendVerificationEmail(email, code, type);
|
||
|
||
if (!emailResult.success) {
|
||
return NextResponse.json(
|
||
{ success: false, error: emailResult.error || '发送邮件失败' },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
|
||
return NextResponse.json({
|
||
success: true,
|
||
message: '验证码已发送,请查收邮件',
|
||
expiresIn: 300, // 5分钟
|
||
});
|
||
} catch (error) {
|
||
console.error('发送验证码失败:', error);
|
||
return NextResponse.json(
|
||
{ success: false, error: '服务器错误' },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|