feat: login page, session management, auth API routes en proxy guard
- lib/session.ts: token generatie, SHA-256 hashing, createSession/getCurrentUser/invalidateSession - app/api/auth/login: bcrypt verificatie, session aanmaken, ops_session cookie (httpOnly, sameSite=strict, 24h TTL), rate-limit 5/min per IP - app/api/auth/logout: session invalideren en cookie verwijderen - app/login/page.tsx: login form (client component) - proxy.ts: route-protectie – redirect naar /login zonder sessie (middleware.ts is deprecated in Next.js 16) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
cce0f25419
commit
be05724de0
5 changed files with 250 additions and 0 deletions
52
lib/session.ts
Normal file
52
lib/session.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
import 'server-only'
|
||||
import { cookies } from 'next/headers'
|
||||
import { createHash, randomBytes } from 'crypto'
|
||||
import { prisma } from './prisma'
|
||||
|
||||
const COOKIE_NAME = 'ops_session'
|
||||
const SESSION_TTL_MS = 24 * 60 * 60 * 1000
|
||||
|
||||
export function generateSessionToken(): string {
|
||||
return randomBytes(32).toString('hex')
|
||||
}
|
||||
|
||||
export function hashToken(token: string): string {
|
||||
return createHash('sha256').update(token).digest('hex')
|
||||
}
|
||||
|
||||
export async function createSession(userId: string, token: string): Promise<void> {
|
||||
const expiresAt = new Date(Date.now() + SESSION_TTL_MS)
|
||||
await prisma.session.create({
|
||||
data: {
|
||||
user_id: userId,
|
||||
token_hash: hashToken(token),
|
||||
expires_at: expiresAt,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export async function getCurrentUser() {
|
||||
const cookieStore = await cookies()
|
||||
const token = cookieStore.get(COOKIE_NAME)?.value
|
||||
if (!token) return null
|
||||
|
||||
const session = await prisma.session.findUnique({
|
||||
where: { token_hash: hashToken(token) },
|
||||
include: { user: true },
|
||||
})
|
||||
|
||||
if (!session) return null
|
||||
|
||||
if (session.expires_at < new Date()) {
|
||||
await prisma.session.delete({ where: { id: session.id } })
|
||||
return null
|
||||
}
|
||||
|
||||
return session.user
|
||||
}
|
||||
|
||||
export async function invalidateSession(token: string): Promise<void> {
|
||||
await prisma.session.deleteMany({
|
||||
where: { token_hash: hashToken(token) },
|
||||
})
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue