import jwt from 'jsonwebtoken'; import bcrypt from 'bcryptjs'; import { type NextRequest } from 'next/server'; const JWT_SECRET = process.env.JWT_SECRET || 'novalon-cms-secret-key-2024'; const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET || 'novalon-cms-refresh-secret-2024'; const TOKEN_EXPIRY = '24h'; const REFRESH_TOKEN_EXPIRY = '7d'; export interface JwtPayload { userId: string; username: string; role: string; } // ============ 密码工具 ============ export async function hashPassword(password: string): Promise { return bcrypt.hash(password, 10); } export async function verifyPassword(password: string, hash: string): Promise { return bcrypt.compare(password, hash); } // ============ Token 工具 ============ export function generateTokens(payload: JwtPayload): { accessToken: string; refreshToken: string } { const accessToken = jwt.sign(payload, JWT_SECRET, { expiresIn: TOKEN_EXPIRY }); const refreshToken = jwt.sign(payload, JWT_REFRESH_SECRET, { expiresIn: REFRESH_TOKEN_EXPIRY }); return { accessToken, refreshToken }; } export function verifyAccessToken(token: string): JwtPayload { return jwt.verify(token, JWT_SECRET) as JwtPayload; } export function verifyRefreshToken(token: string): JwtPayload { return jwt.verify(token, JWT_REFRESH_SECRET) as JwtPayload; } // ============ 请求认证 ============ export function getTokenFromRequest(request: NextRequest): string | null { const authHeader = request.headers.get('authorization'); if (authHeader?.startsWith('Bearer ')) { return authHeader.slice(7); } return null; } export function authenticateRequest(request: NextRequest): JwtPayload | null { const token = getTokenFromRequest(request); if (!token) return null; try { return verifyAccessToken(token); } catch { return null; } } // ============ Cookie 工具 ============ export function setTokenCookie(response: Response, accessToken: string, refreshToken: string): void { response.headers.set( 'Set-Cookie', `novalon_token=${accessToken}; Path=/; HttpOnly; SameSite=Lax; Max-Age=86400` ); response.headers.append( 'Set-Cookie', `novalon_refresh=${refreshToken}; Path=/; HttpOnly; SameSite=Lax; Max-Age=604800` ); } export function clearTokenCookie(response: Response): void { response.headers.set( 'Set-Cookie', `novalon_token=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0` ); response.headers.append( 'Set-Cookie', `novalon_refresh=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0` ); }