Extract shared auth logic and validation rules to shared/auth.ts Introduce utility functions for HTTP errors and user input parsing Standardize error messages and date formatting across the app
75 lines
1.6 KiB
TypeScript
75 lines
1.6 KiB
TypeScript
import type { H3Event } from 'h3'
|
|
|
|
import { normalizeUsername, type UserRole } from '~~/shared/auth'
|
|
|
|
import { createUserSession, destroyUserSession, getUserSession } from './session'
|
|
import { getUserById, updateLastLogin, type UserAuthRecord } from './user-repository'
|
|
|
|
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
|
|
}
|