feat: implement auth system, passkeys, and user management
Add PostgreSQL and Redis integration for users and sessions Implement password and WebAuthn passkey login flows Add Docker stack, super-admin seeding, and protected routes
This commit is contained in:
78
server/utils/auth.ts
Normal file
78
server/utils/auth.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { H3Event } from 'h3'
|
||||
|
||||
import type { UserRole } from '~~/shared/auth'
|
||||
|
||||
import { createUserSession, destroyUserSession, getUserSession } from './session'
|
||||
import { getUserById, updateLastLogin, type UserAuthRecord } from './user-repository'
|
||||
|
||||
export function normalizeUsername(value: string) {
|
||||
return value.trim().toLowerCase()
|
||||
}
|
||||
|
||||
export async function getAuthContext(event: H3Event): Promise<{
|
||||
session: Awaited<ReturnType<typeof getUserSession>>
|
||||
user: UserAuthRecord
|
||||
} | null> {
|
||||
const session = await getUserSession(event)
|
||||
|
||||
if (!session) {
|
||||
return null
|
||||
}
|
||||
|
||||
const user = await getUserById(session.userId)
|
||||
|
||||
if (!user || !user.isActive) {
|
||||
await destroyUserSession(event)
|
||||
return null
|
||||
}
|
||||
|
||||
return {
|
||||
session,
|
||||
user
|
||||
}
|
||||
}
|
||||
|
||||
export async function requireAuth(event: H3Event) {
|
||||
const auth = await getAuthContext(event)
|
||||
|
||||
if (!auth) {
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
statusMessage: 'Authentication required'
|
||||
})
|
||||
}
|
||||
|
||||
return auth
|
||||
}
|
||||
|
||||
export async function requireRole(event: H3Event, role: UserRole) {
|
||||
const auth = await requireAuth(event)
|
||||
|
||||
if (auth.user.role !== role) {
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: 'You are not allowed to perform this action'
|
||||
})
|
||||
}
|
||||
|
||||
return auth
|
||||
}
|
||||
|
||||
export async function signInUser(event: H3Event, user: UserAuthRecord, remember: boolean) {
|
||||
await createUserSession(event, {
|
||||
userId: user.id,
|
||||
remember
|
||||
})
|
||||
await updateLastLogin(user.id)
|
||||
|
||||
const refreshedUser = await getUserById(user.id)
|
||||
|
||||
if (!refreshedUser) {
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Unable to load authenticated user'
|
||||
})
|
||||
}
|
||||
|
||||
return refreshedUser
|
||||
}
|
||||
Reference in New Issue
Block a user