nuxt-auth-kit
v1.2.1
Published
Nuxt module for authentication with Laravel API — login, register, profile, password management, roles & permissions
Maintainers
Readme
nuxt-auth-kit
专为 Laravel API 设计的开箱即用 Nuxt 认证模块。 安装一次 — 登录、注册、个人资料、密码、角色与权限均已就绪。
阅读其他语言版本: 🇬🇧 English · 🇫🇷 Français · 🇸🇦 العربية · 🇪🇸 Español · 🇩🇪 Deutsch
功能特性
- ✅ 登录 / 退出登录,通过安全 Cookie 持久化会话
- ✅ 注册(含密码确认)
- ✅ 已登录用户信息 (
useAuth().user) - ✅ 个人资料更新(姓名、邮箱、头像)
- ✅ 修改密码
- ✅ 忘记密码(发送邮件)
- ✅ 重置密码(通过 token)
- ✅ 角色与权限管理 (RBAC) —
hasRole()、hasPermission() - ✅ 命名中间件:
auth、guest、role - ✅ 7 个分屏 Vue 组件 — 自动导入,Tailwind CSS
- ✅ 完整 TypeScript 支持
- ✅ 可配置主题 (每个组件的
uiprop) — 颜色、圆角、按钮、布局 - ✅ 电话号码输入 —
PhoneInput组件,支持国家选择器、国旗、自动格式化 (E.164) - ✅
exceptprop 用于RegisterForm&UpdateProfileForm— 动态隐藏/排除字段
安装
npm install nuxt-auth-kit
# 或
yarn add nuxt-auth-kit
# 或
pnpm add nuxt-auth-kit需要
@nuxt/ui提供样式。兼容 Nuxt 3.x 和 Nuxt 4.x。
PhoneInput 组件还需安装
libphonenumber-js:npm install libphonenumber-js
配置
// nuxt.config.ts
export default defineNuxtConfig({
modules: ["nuxt-auth-kit", "@nuxt/ui"],
nuxtAuthKit: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || "http://localhost:8000",
endpoints: {
login: "/api/auth/login",
register: "/api/auth/register",
logout: "/api/auth/logout",
me: "/api/auth/me",
updateProfile: "/api/profile",
updatePassword: "/api/profile/password",
forgotPassword: "/api/auth/forgot-password",
resetPassword: "/api/auth/reset-password",
},
redirects: {
login: "/auth/login",
home: "/",
afterLogout: "/auth/login",
},
tokenCookieName: "auth_token",
rbac: {
superAdminRole: "super-admin",
defaultUserRole: "user",
},
},
});# .env
NUXT_PUBLIC_API_BASE=https://api.myproject.com使用方法
认证页面
<!-- pages/auth/login.vue -->
<template>
<AuthLayout :quote="quote">
<AuthLoginForm
:show-social="true"
@forgot-password="navigateTo('/auth/forgot-password')"
@register="navigateTo('/auth/register')"
@google-login="handleGoogleLogin"
@apple-login="handleAppleLogin"
/>
</AuthLayout>
</template>
<script setup lang="ts">
definePageMeta({ middleware: "guest" });
const quote = {
text: "流畅愉快的体验。",
author: "3S Tech Group",
location: "达喀尔",
};
async function handleGoogleLogin() {
// 重定向到你的 Google OAuth 提供商(例如:Supabase、Laravel Socialite 等)
// await navigateTo('/auth/google', { external: true })
console.log("已触发 Google 登录");
}
async function handleAppleLogin() {
// 重定向到你的 Apple OAuth 提供商
// await navigateTo('/auth/apple', { external: true })
console.log("已触发 Apple 登录");
}
</script><!-- pages/auth/register.vue -->
<template>
<AuthLayout>
<!-- 默认:密码必填,不显示手机号 -->
<AuthRegisterForm />
<!-- 不需要密码 -->
<AuthRegisterForm :except="['password']" />
<!-- 不显示手机号 -->
<AuthRegisterForm :except="['phone']" @login="navigateTo('/auth/login')" />
<!-- 不显示手机号且不需要密码 -->
<AuthRegisterForm
:except="['password', 'phone']"
@login="navigateTo('/auth/login')"
/>
</AuthLayout>
</template>
<script setup lang="ts">
definePageMeta({ middleware: "guest" });
</script><!-- pages/auth/forgot-password.vue -->
<template>
<AuthLayout>
<AuthForgotPasswordForm @back-to-login="navigateTo('/auth/login')" />
</AuthLayout>
</template>
<script setup lang="ts">
definePageMeta({ middleware: "guest" });
</script><!-- pages/auth/reset-password.vue -->
<template>
<AuthLayout>
<!-- 自动从 URL 中读取 ?token= 和 ?email= -->
<AuthResetPasswordForm @back-to-login="navigateTo('/auth/login')" />
</AuthLayout>
</template>
<script setup lang="ts">
definePageMeta({ middleware: "guest" });
</script>个人资料页面
<!-- pages/profile/index.vue -->
<template>
<div class="max-w-2xl mx-auto py-10 px-4 space-y-10">
<!-- 默认:名字、姓氏、邮箱可见 -->
<ProfileUpdateForm
title="我的资料"
:show-avatar="true"
@success="onProfileSaved"
/>
<!-- 显示手机号,不显示邮箱 -->
<ProfileUpdateForm :except="['email']" @success="onProfileSaved" />
<!-- 仅显示姓名 -->
<ProfileUpdateForm :except="['email', 'phone']" @success="onProfileSaved" />
</div>
</template>
<script setup lang="ts">
definePageMeta({ middleware: "auth" });
function onProfileSaved() {
// 例如:显示一个 toast 通知
}
</script>useAuth 组合式函数
所有内容均自动导入 — 无需在文件中手动 import。
const {
user, // Ref<AuthUser | null>
isAuthenticated, // ComputedRef<boolean>
isGuest, // ComputedRef<boolean>
loading, // Ref<boolean>
// 操作
login,
register,
logout,
fetchUser,
updateProfile,
updatePassword,
forgotPassword,
resetPassword,
// RBAC
hasRole, // (role: string | string[]) => boolean
hasPermission, // (perm: string | string[]) => boolean
} = useAuth();RBAC 示例
const { hasRole, hasPermission } = useAuth();
if (hasRole("admin")) {
/* ... */
}
if (hasRole(["admin", "manager"])) {
/* ... */
}
if (hasPermission("edit-posts")) {
/* ... */
}<template>
<AdminPanel v-if="hasRole('admin')" />
<button v-if="hasPermission('create-post')">创建文章</button>
</template>
super-admin角色(可通过rbac.superAdminRole配置)会绕过role中间件中的所有检查。
中间件
// 仅限已登录用户
definePageMeta({ middleware: "auth" });
// 仅限访客 — 已登录则重定向至 /
definePageMeta({ middleware: "guest" });
// 基于角色的访问
definePageMeta({ middleware: "role", roles: ["admin", "manager"] });
// 认证 + 角色组合
definePageMeta({ middleware: ["auth", "role"], roles: ["admin"] });预期的 Laravel API
所有端点可通过 nuxtAuthKit.endpoints 自定义。
| 方法 | 路由 | Auth | 响应 | 说明 |
| ------ | --------------------------- | ---- | ----------------- | ------------- |
| POST | /api/auth/login | — | { user, token } | 登录 |
| POST | /api/auth/register | — | { user, token } | 注册 |
| POST | /api/auth/logout | ✅ | { message } | 退出登录 |
| GET | /api/auth/me | ✅ | { user } | 当前用户 |
| PUT | /api/profile | ✅ | { user } | 更新资料 |
| PUT | /api/profile/password | ✅ | { message } | 修改密码 |
| POST | /api/auth/forgot-password | — | { message } | 发送重置邮件 |
| POST | /api/auth/reset-password | — | { message } | 用 token 重置 |
user字段必须至少包含id、name、roles和permissions字段(字符串数组)为启用 RBAC 的可选字段。
Laravel Sanctum 示例
// routes/api.php
Route::prefix('auth')->group(function () {
Route::post('login', [AuthController::class, 'login']);
Route::post('register', [AuthController::class, 'register']);
Route::post('forgot-password', [AuthController::class, 'forgotPassword']);
Route::post('reset-password', [AuthController::class, 'resetPassword']);
Route::middleware('auth:sanctum')->group(function () {
Route::post('logout', [AuthController::class, 'logout']);
Route::get('me', [AuthController::class, 'me']);
Route::put('profile', [AuthController::class, 'updateProfile']);
Route::put('password', [AuthController::class, 'updatePassword']);
});
});// AuthController.php
public function me(Request $request): JsonResponse
{
return response()->json([
'user' => $request->user()->load('roles', 'permissions'),
]);
}TypeScript 类型
import type {
AuthUser, // 用户结构
LoginCredentials, // { email, password, remember? }
RegisterData, // { name, email, password, password_confirmation }
UpdateProfileData, // { name?, email?, avatar? }
UpdatePasswordData, // { current_password, new_password, new_password_confirmation }
ForgotPasswordData, // { email }
ResetPasswordData, // { token, email, password, password_confirmation }
AuthResponse, // { user, token }
ApiError, // { message, errors? }
ModuleOptions, // nuxtAuthKit 配置
} from "nuxt-auth-kit";主题与样式
每个组件都接受 ui prop 来部分覆盖样式。
<AuthLoginForm
:ui="{
inputRounded: 'rounded-lg',
btnColor: 'primary',
titleColor: 'text-slate-900',
accentColor: 'text-blue-600',
}"
/>
<AuthLayout
:ui="{
layoutPageColor: '#1e293b',
layoutTextColor: '#f8fafc',
layoutTaglineColor: 'rgba(248,250,252,0.7)',
}"
/>FormTheme tokens
| 参数 | 默认值 | 说明 |
| --------------------- | ------------------------ | ---------- |
| inputRounded | rounded-full | 输入框圆角 |
| color | neutral | 输入框颜色 |
| btnRounded | rounded-full | 按钮圆角 |
| btnColor | neutral | 按钮颜色 |
| btnVariant | solid | 按钮样式 |
| btnSecondaryColor | secondary | 次按钮颜色 |
| btnSecondaryVariant | subtle | 次按钮样式 |
| btnSecondaryRounded | rounded-full | 次按钮圆角 |
| titleColor | text-[#1a2e1a] | 标题颜色 |
| subtitleColor | text-[#6b7c6b] | 副标题颜色 |
| accentColor | text-[#1B4332] | 强调色 |
| roleRingColor | ring-[#1B4332] | 激活边框 |
| layoutPageColor | #eeeee6 | 页面背景 |
| layoutTextColor | #ffffff | 文本颜色 |
| layoutTaglineColor | rgba(255,255,255,0.75) | 标语颜色 |
PhoneInput
<PhoneInput
v-model="form.phone"
v-model:country-code="form.phoneCountry"
:preferred-countries="['SN', 'FR', 'CI', 'MA']"
@data="onPhoneData"
/>@data 事件的数据结构
{
e164: '+221771234567', // E.164 格式 → 存储到数据库
countryCode: 'SN', // 国家代码
formatted: '77 123 45 67', // 本地格式
isValid: true, // 是否为有效号码
}架构
nuxt-auth-kit/
├── build.config.ts
├── package.json
└── src/
├── module.ts
└── runtime/
├── types/index.ts
├── stores/auth.ts
├── composables/useAuth.ts
├── plugins/auth.ts
├── middleware/
│ ├── auth.ts
│ ├── guest.ts
│ └── role.ts
└── components/
├── auth/
│ ├── AuthLayout.vue
│ ├── LoginForm.vue
│ ├── RegisterForm.vue
│ ├── ForgotPasswordForm.vue
│ └── ResetPasswordForm.vue
├── profile/
│ ├── UpdateProfileForm.vue
│ └── UpdatePasswordForm.vue
└── ui/
└── PhoneInput.vue # 🆕 v1.2.0
# composables/useFormTheme.ts 🆕 v1.2.0MIT 许可证 · 由 3S Tech Group 用 ❤️ 制作 📦 npm · 💻 GitHub · 📖 文档
