1.nuxt-auth-utils
npx nuxi module add nuxt-auth-utils
// server/routes/auth/github.get.ts
export default defineOAuthGitHubEventHandler({
config: {
emailRequired: true,
},
async onSuccess(event, { user, tokens }) {
await setUserSession(event, {
user: {
id: user.id.toString(),
name: user.login,
email: user.email,
avatar: user.avatar_url,
},
})
return sendRedirect(event, '/dashboard')
},
onError(event, error) {
console.error('GitHub OAuth error:', error)
return sendRedirect(event, '/login?error=oauth')
},
})
// server/routes/auth/google.get.ts
export default defineOAuthGoogleEventHandler({
async onSuccess(event, { user }) {
await setUserSession(event, {
user: {
id: user.sub,
name: user.name,
email: user.email,
avatar: user.picture,
},
})
return sendRedirect(event, '/dashboard')
},
})
2. セッション管理
<script setup lang="ts">
const { loggedIn, user, session, clear } = useUserSession()
</script>
<template>
<div v-if="loggedIn">
<img :src="user?.avatar" :alt="user?.name" class="w-8 h-8 rounded-full" />
<span>{{ user?.name }}</span>
<button @click="clear()">Đăng xuất</button>
</div>
<div v-else>
<a href="/auth/github">Login with GitHub</a>
<a href="/auth/google">Login with Google</a>
</div>
</template>
3. 認証情報によるログイン
// server/api/auth/login.post.ts
import bcrypt from 'bcryptjs'
export default defineEventHandler(async (event) => {
const { email, password } = await readBody(event)
const user = await db.query.users.findFirst({
where: eq(users.email, email),
})
if (!user || !await bcrypt.compare(password, user.hashedPassword)) {
throw createError({ statusCode: 401, message: 'Email hoặc mật khẩu sai' })
}
await setUserSession(event, {
user: { id: user.id, name: user.name, email: user.email, role: user.role },
})
return { success: true }
})
4. 保護されたルート
// server/utils/auth.ts
export async function requireAuth(event: H3Event) {
const session = await getUserSession(event)
if (!session.user) {
throw createError({ statusCode: 401, message: 'Unauthorized' })
}
return session.user
}
export async function requireRole(event: H3Event, role: string) {
const user = await requireAuth(event)
if (user.role !== role) {
throw createError({ statusCode: 403, message: 'Forbidden' })
}
return user
}
// server/api/admin/users.get.ts
export default defineEventHandler(async (event) => {
await requireRole(event, 'admin')
return db.query.users.findMany()
})
5. 認証ミドルウェア
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to) => {
const { loggedIn } = useUserSession()
if (!loggedIn.value) {
return navigateTo(`/login?redirect=${to.fullPath}`)
}
})
// middleware/guest.ts — redirect if already logged in
export default defineNuxtRouteMiddleware(() => {
const { loggedIn } = useUserSession()
if (loggedIn.value) {
return navigateTo('/dashboard')
}
})
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
session: {
maxAge: 60 * 60 * 24 * 7, // 7 days
},
oauth: {
github: {
clientId: '',
clientSecret: '',
},
google: {
clientId: '',
clientSecret: '',
},
},
},
})
次の記事: Nuxt のデータベースと ORM — 霧雨の ORM、移行、CRUD。