forked from hazem/yslootahrobotics
- Implemented Prisma schema with models for AdminUser, AppSettings, and Snapshot. - Created seed script to initialize the database with an admin user and JWT secret. - Developed admin login page with form handling and error management. - Added API routes for admin login, logout, change password, and JWT verification. - Integrated Stripe for payment intent management in admin orders. - Established middleware for protecting admin routes with JWT authentication. - Created Zustand stores for managing persona and snapshot states.
50 lines
1.6 KiB
TypeScript
50 lines
1.6 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import bcrypt from 'bcryptjs';
|
|
import { SignJWT } from 'jose';
|
|
import { prisma } from '@/lib/prisma';
|
|
|
|
export async function POST(request: Request) {
|
|
try {
|
|
const { username, password } = await request.json();
|
|
|
|
if (!username || !password) {
|
|
return NextResponse.json({ error: 'Username and password are required' }, { status: 400 });
|
|
}
|
|
|
|
const user = await prisma.adminUser.findUnique({ where: { username } });
|
|
if (!user) {
|
|
return NextResponse.json({ error: 'Invalid credentials' }, { status: 401 });
|
|
}
|
|
|
|
const valid = await bcrypt.compare(password, user.passwordHash);
|
|
if (!valid) {
|
|
return NextResponse.json({ error: 'Invalid credentials' }, { status: 401 });
|
|
}
|
|
|
|
const jwtSecret = process.env.ADMIN_JWT_SECRET;
|
|
if (!jwtSecret) {
|
|
return NextResponse.json({ error: 'Server configuration error' }, { status: 500 });
|
|
}
|
|
|
|
const secret = new TextEncoder().encode(jwtSecret);
|
|
const token = await new SignJWT({ sub: user.id, username: user.username })
|
|
.setProtectedHeader({ alg: 'HS256' })
|
|
.setIssuedAt()
|
|
.setExpirationTime('7d')
|
|
.sign(secret);
|
|
|
|
const response = NextResponse.json({ success: true });
|
|
response.cookies.set('admin_token', token, {
|
|
httpOnly: true,
|
|
secure: process.env.NODE_ENV === 'production',
|
|
sameSite: 'lax',
|
|
maxAge: 60 * 60 * 24 * 7, // 7 days
|
|
path: '/',
|
|
});
|
|
|
|
return response;
|
|
} catch {
|
|
return NextResponse.json({ error: 'Internal server error' }, { status: 500 });
|
|
}
|
|
}
|