import { NextRequest, NextResponse } from 'next/server' import { createToken } from '@/lib/auth' import { initDatabase } from '@/lib/db-schema' import { signSharedJwt, sharedCookieConfig } from '@/lib/jwt-shared' import { ldapAuth } from '@/lib/ldap' import { getDb } from '@/lib/db' import bcrypt from 'bcryptjs' export async function POST(request: NextRequest) { try { initDatabase() const { username, password } = await request.json() if (!username || !password) return NextResponse.json({ error: '请输入用户名和密码' }, { status: 400 }) let userId: number let role: string let displayName: string const db = getDb() // 1. localadmin:纯本地 BCrypt,不依赖 LLDAP if (username === 'localadmin') { const localUser = db.prepare( 'SELECT * FROM users WHERE username = ? AND is_active = 1' ).get(username) as { id: number; username: string; display_name: string; role: string; password_hash: string } | undefined if (!localUser || !bcrypt.compareSync(password, localUser.password_hash)) { return NextResponse.json({ error: '用户名或密码错误' }, { status: 401 }) } userId = localUser.id role = localUser.role displayName = localUser.display_name || username } else { // 2. 其他用户:LLDAP 优先 const ldapResult = await ldapAuth(username, password) if (ldapResult.success) { // LDAP 认证成功 → 更新本地密码缓存 + 自动创建用户 displayName = ldapResult.displayName || username const pwHash = bcrypt.hashSync(password, 10) const existing = db.prepare( 'SELECT id, role FROM users WHERE username = ? AND is_active = 1' ).get(username) as { id: number; role: string } | undefined if (existing) { db.prepare('UPDATE users SET password_hash = ?, display_name = ? WHERE id = ?') .run(pwHash, displayName, existing.id) userId = existing.id role = existing.role } else { db.prepare( "INSERT INTO users (username, password_hash, display_name, role, is_active, created_at, updated_at) VALUES (?, ?, ?, 'viewer', 1, datetime('now', '+8 hours'), datetime('now', '+8 hours'))" ).run(username, pwHash, displayName) const created = db.prepare( 'SELECT id, role FROM users WHERE username = ?' ).get(username) as { id: number; role: string } | undefined if (!created) return NextResponse.json({ error: '用户创建失败' }, { status: 500 }) userId = created.id role = created.role } } else if (ldapResult.unreachable) { // LLDAP 不可达 → 回退本地密码缓存 const localUser = db.prepare( 'SELECT * FROM users WHERE username = ? AND is_active = 1' ).get(username) as { id: number; username: string; display_name: string; role: string; password_hash: string } | undefined if (!localUser || !bcrypt.compareSync(password, localUser.password_hash)) { return NextResponse.json({ error: '认证服务不可用,且本地密码不匹配' }, { status: 401 }) } userId = localUser.id role = localUser.role displayName = localUser.display_name || username } else { return NextResponse.json({ error: '用户名或密码错误' }, { status: 401 }) } } // 3. 更新最后登录时间和活跃时间 db.prepare("UPDATE users SET last_login_at = datetime('now', '+8 hours'), last_active_at = datetime('now', '+8 hours') WHERE id = ?").run(userId) // 4. 签发两个 cookie const localToken = await createToken({ id: userId, username, display_name: displayName, role }) const sharedToken = signSharedJwt({ username, displayName }) const sharedCfg = sharedCookieConfig() const response = NextResponse.json({ user: { id: userId, username, display_name: displayName, role }, }) response.cookies.set('session_issue', localToken, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 7 * 24 * 60 * 60, path: '/', }) response.cookies.set(sharedCfg.name, sharedToken, sharedCfg) return response } catch (e) { console.error('Login error:', e); return NextResponse.json({ error: '登录失败' }, { status: 500 }) } }