为你的 Nuxt 3 和 Vue 3 应用添加身份验证 (Logto)
Source: Dev.to
(请提供需要翻译的正文内容,我才能为您完成简体中文翻译。)
开始之前:在控制台创建 Logto 应用
在 Logto 控制台中,创建一个与您的框架相匹配的应用:
| 框架 | Logto 应用类型 |
|---|---|
| Nuxt 3 | Traditional Web |
| Vue 3 | Single Page Application (SPA) |
您需要以下两个设置的值:
- Endpoint – 您的租户 URL(例如
https://your-tenant.logto.app) - App ID
- App Secret – 仅适用于 Nuxt
第 1 部分 — Nuxt 3(SSR):使用 @logto/nuxt 添加认证
Nuxt 通常以 SSR(或混合渲染)方式部署。Logto 的 Nuxt SDK 为 SSR 设计,使用安全的 cookie + 服务器端处理来完成认证。
1️⃣ 安装 Nuxt SDK
npm i @logto/nuxt
# or
pnpm add @logto/nuxt
# or
yarn add @logto/nuxt
2️⃣ 添加环境变量
在项目根目录创建 .env 文件:
NUXT_LOGTO_ENDPOINT="https://your-tenant.logto.app"
NUXT_LOGTO_APP_ID="your-app-id"
NUXT_LOGTO_APP_SECRET="your-app-secret"
NUXT_LOGTO_COOKIE_ENCRYPTION_KEY="a-strong-random-string"
重要提示:
NUXT_LOGTO_COOKIE_ENCRYPTION_KEY必须是强随机字符串,因为它用于保护加密的认证 cookie。
3️⃣ 配置 nuxt.config.ts
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@logto/nuxt'],
runtimeConfig: {
logto: {
endpoint: process.env.NUXT_LOGTO_ENDPOINT,
appId: process.env.NUXT_LOGTO_APP_ID,
appSecret: process.env.NUXT_LOGTO_APP_SECRET,
cookieEncryptionKey: process.env.NUXT_LOGTO_COOKIE_ENCRYPTION_KEY,
},
},
})
4️⃣ 在 Logto 控制台配置重定向 URI
假设你的 Nuxt 应用运行在 http://localhost:3000:
| 重定向类型 | URI |
|---|---|
| Redirect URI(登录回调) | http://localhost:3000/callback |
| Post sign‑out redirect URI(登出后重定向) | http://localhost:3000/ |
这些必须与 SDK 使用的回调和返回 URL 完全匹配。
5️⃣ 了解内置路由
Nuxt 模块会提供以下内置路由用于认证流程:
/sign-in/sign-out/callback
你可以自定义它们:
// nuxt.config.ts
export default defineNuxtConfig({
logto: {
pathnames: {
signIn: '/login',
signOut: '/logout',
callback: '/auth/callback',
},
},
})
如果修改了回调路径,请相应地在 Logto 控制台更新重定向 URI。
6️⃣ 实现简易的登录 / 登出按钮
<script setup lang="ts">
const user = useLogtoUser()
</script>
<template>
<button @click="user ? signOut() : signIn()">
Sign {{ user ? 'out' : 'in' }}
</button>
<pre>{{ user }}</pre>
</template>
useLogtoUser() 是响应式的 — 会在会话变化时自动更新。
7️⃣ 请求额外的用户声明(Scopes)
默认情况下你只能获取基础 OIDC 声明。若想获取更多(例如 email、phone),需要添加 scopes:
// nuxt.config.ts
import { UserScope } from '@logto/nuxt'
export default defineNuxtConfig({
logto: {
scopes: [UserScope.Email, UserScope.Phone],
},
})
8️⃣ 使用 Logto 客户端(仅服务器端)
useLogtoClient() 只能在服务器端使用;在客户端会返回 undefined。示例:在服务器端获取一次用户信息。
// composables/useServerUserInfo.ts
import { useLogtoClient, useState, callOnce } from '#imports'
export const useServerUserInfo = async () => {
const client = useLogtoClient()
const userInfo = useState('logto-user-info', () => null)
await callOnce(async () => {
if (!client) return
if (!(await client.isAuthenticated())) return
userInfo.value = await client.fetchUserInfo()
})
return userInfo
}
Source: …
第 2 部分 — Vue 3(SPA):使用 Vue SDK 添加身份验证
Vue SPA 没有服务器运行时来安全地存储密钥,因此推荐的设置是使用 Logto Vue SDK 并在 Logto 控制台中配置 SPA 应用设置。
1️⃣ 安装 Vue SDK
npm i @logto/vue
# or
pnpm add @logto/vue
# or
yarn add @logto/vue
2️⃣ 在 Logto 控制台配置重定向 URI
假设你的 Vue 应用运行在 http://localhost:5173:
| 重定向类型 | URI |
|---|---|
| Redirect URI(登录回调) | http://localhost:5173/callback |
| Post sign‑out redirect URI(退出后重定向) | http://localhost:5173/ |
(如果你的开发服务器地址不同,请使用实际的源地址。)
3️⃣ 在 main.ts 中初始化 Logto
// src/main.ts
import { createApp } from 'vue'
import { createLogto } from '@logto/vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(
createLogto({
endpoint: import.meta.env.VITE_LOGTO_ENDPOINT,
appId: import.meta.env.VITE_LOGTO_APP_ID,
})
)
app.use(router)
app.mount('#app')
4️⃣ 添加环境变量
创建一个 .env 文件(Vite 会公开以 VITE_ 为前缀的变量):
VITE_LOGTO_ENDPOINT="https://your-tenant.logto.app"
VITE_LOGTO_APP_ID="your-app-id"
添加回调路由
在单页面应用(SPA)中,您必须处理重定向回调路由。
使用 Vue Router 的示例
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import Home from '../pages/Home.vue'
import Callback from '../pages/Callback.vue'
export default createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/callback', component: Callback },
],
})
回调页面
<script setup lang="ts">
import { onMounted } from 'vue'
import { useLogto } from '@logto/vue'
import { useRouter } from 'vue-router'
const { handleSignInCallback } = useLogto()
const router = useRouter()
onMounted(async () => {
await handleSignInCallback(window.location.href)
router.replace('/')
})
</script>
<template>
<p>Signing you in…</p>
</template>
登录 / 登出 按钮
<script setup lang="ts">
import { useLogto } from '@logto/vue'
const { isAuthenticated, signIn, signOut } = useLogto()
const handleSignIn = async () => {
await signIn(import.meta.env.VITE_LOGTO_REDIRECT_URI)
}
const handleSignOut = async () => {
await signOut(import.meta.env.VITE_LOGTO_POST_SIGN_OUT_REDIRECT_URI)
}
</script>
<template>
<button @click="handleSignIn" v-if="!isAuthenticated">Sign in</button>
<button @click="handleSignOut" v-else>Sign out</button>
</template>
添加重定向相关的环境变量
VITE_LOGTO_REDIRECT_URI="http://localhost:5173/callback"
VITE_LOGTO_POST_SIGN_OUT_REDIRECT_URI="http://localhost:5173/"
显示当前用户(可选)
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useLogto } from '@logto/vue'
const { isAuthenticated, getIdTokenClaims } = useLogto()
const claims = ref(null)
const loadClaims = async () => {
claims.value = await getIdTokenClaims()
}
</script>
<template>
<button @click="loadClaims" :disabled="!isAuthenticated">Load user claims</button>
<pre v-if="claims">{{ claims }}</pre>
</template>
在 Nuxt 与 Vue 集成之间的选择
- Nuxt(SSR 或混合渲染): 使用
@logto/nuxt。它专为服务器端流程和安全 Cookie 处理而构建。 - Vue SPA(无服务器运行时): 使用
@logto/vue,并在 Logto 控制台中选择 SPA 应用类型。
快速检查
- 点击 Sign in 应该将您重定向到 Logto 托管的登录界面。
- 登录后,您应该进入回调路由并返回到应用。
- 点击 Sign out 应该清除共享会话并重定向到登出后的 URL。
最终说明
本文故意保持示例简洁且面向生产。认证成功后,下一步通常是:
- 保护路由(Nuxt 中间件 / Vue 路由守卫)
- 使用访问令牌调用您的 API
- 如果产品需要,添加组织/角色/权限