ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

在 Convex 聊天应用中集成 Clerk 用户认证:clerk-initial-auth 示例全解析

在 Convex 聊天应用中集成 Clerk 用户认证:clerk-initial-auth 示例全解析 在 Convex 聊天应用中集成 Clerk 用户认证clerk-initial-auth 示例全解析【免费下载链接】convex-backendThe open-source reactive database for app developers项目地址: https://gitcode.com/gh_mirrors/co/convex-backend本篇文章基于 convex-backend 仓库中的 clerk-initial-auth 示例完整讲解如何为一个 Convex 聊天应用接入 Clerk 身份认证从前端登录按钮、认证 Provider 桥接到后端函数中的身份校验与消息归属再到切换为自己 Clerk 实例的完整配置。读完本文你将掌握「Convex Clerk」从零到一的最小可运行认证闭环并能基于示例代码快速改造成自己的认证流程。示例要解决的问题让每条消息都有主人clerk-initial-auth 是一个聚焦单一目标的最小示例给一个基础聊天应用加上用户与认证能力。README 描述的行为闭环非常清晰应用启动后用户首先看到的是一个Log In登录按钮用户登录成功后其身份信息被持久化到数据库README 描述为持久化到users表用户发送的每条消息都与发送它的用户关联用户可以通过Log Out登出按钮退出登录。也就是说这个示例演示的是一条完整的「认证状态驱动应用行为」链路而不是一个孤立的登录弹窗。认证框架选型为 Clerk——一个托管式身份认证服务负责注册、登录、会话管理等繁琐环节而 Convex 侧则专注于身份校验与数据读写。示例的完整文件结构如下npm-packages/private-demos/clerk-initial-auth/ ├── convex/ │ ├── _generated/ # Convex 自动生成的类型与 API 绑定 │ ├── auth.config.ts # 认证提供方配置Clerk Issuer │ ├── messages.ts # 消息相关的 query / mutation │ └── schema.ts # 数据库 schema 定义 ├── src/ │ ├── main.tsx # 应用入口ClerkProvider ConvexProviderWithClerk │ ├── App.tsx # 登录状态驱动的根组件 │ ├── LoginPage.tsx # 未登录页面SignInButton │ ├── Badge.tsx # 已登录用户信息徽章 │ └── index.css ├── index.html ├── package.json └── vite.config.mts快速运行示例运行示例只需要一条命令在 package.json 中定义npm run dev该命令实际执行的是convex dev --start vite --open它做了两件事启动 Convex 本地开发环境convex dev会监听convex/目录下的函数并自动部署同时拉起 Vite 开发服务器并自动打开浏览器vite --open。示例的前端依赖集中在 package.json 中核心包括convexworkspace 内部版本Convex 客户端与类型系统clerk/reactClerk 的 React 绑定提供ClerkProvider、SignInButton、useAuth、useUser等react/react-domReact 18vitevitejs/plugin-react前端构建与开发服务器。认证配置的两把钥匙Publishable Key 与 Issuer URLREADME 的 Using your own Clerk instance 一节明确指出接入自己的 Clerk 实例需要两个关键配置配置项用途在示例中的位置Publishable Key可发布密钥Clerk 前端 SDK 初始化凭证标识你的 Clerk 应用src/main.tsxJWT Template Issuer URLJWT 模板签发者地址Convex 后端校验 Clerk 签发的 JWT 时使用convex/auth.config.ts这两个配置的获取方式README 指向了 Convex 官方文档中 Clerk 的 Get Started 流程在 Clerk Dashboard 中创建应用、配置 JWT 模板随后获得 Publishable Key 与 Issuer URL。前端侧Publishable Key在 src/main.tsx 中Publishable Key 直接传给ClerkProviderimport { ClerkProvider, useAuth } from clerk/react; import { ConvexReactClient } from convex/react; import { ConvexProviderWithClerk } from convex/react-clerk; import { StrictMode } from react; import ReactDOM from react-dom/client; import App from ./App; import ./index.css; const convex new ConvexReactClient(import.meta.env.VITE_CONVEX_URL); ReactDOM.createRoot(document.getElementById(root)!).render( StrictMode ClerkProvider // Replace this with your Clerk Publishable Key // or with {import.meta.env.VITE_CLERK_PUBLISHABLE_KEY} // and configure VITE_CLERK_PUBLISHABLE_KEY in your .env.local publishableKeypk_test_cm9idXN0LW1hZ2dvdC0yOS5jbGVyay5hY2NvdW50cy5kZXYk ConvexProviderWithClerk client{convex} useAuth{useAuth} App / /ConvexProviderWithClerk /ClerkProvider /StrictMode, );代码注释给出了两种取值方式直接硬编码或通过环境变量import.meta.env.VITE_CLERK_PUBLISHABLE_KEY配置在.env.local中。推荐后者避免把密钥写进源码。后端侧Issuer URL在 convex/auth.config.ts 中Issuer URL 配置在 Convex 的AuthConfig里import { AuthConfig } from convex/server; export default { providers: [ { // Replace with your own Clerk Issuer URL from your convex JWT template // or with process.env.CLERK_JWT_ISSUER_DOMAIN // and configure CLERK_JWT_ISSUER_DOMAIN on the Convex Dashboard // See https://docs.convex.dev/auth/clerk#configuring-dev-and-prod-instances domain: https://robust-maggot-29.clerk.accounts.dev, applicationID: convex, }, ], } satisfies AuthConfig;关键字段说明domainClerk 为你生成的 JWT 模板 Issuer URL形如https://你的实例.clerk.accounts.dev。它同时是 OIDC 签发者地址Convex 后端依赖它拉取 Clerk 的公钥并验证 JWT 签名。生产环境建议改用process.env.CLERK_JWT_ISSUER_DOMAIN并在 Convex Dashboard 上配置同名环境变量以区分开发与生产实例applicationID对应 Clerk JWT 模板中的 Audience受众示例中为convex。后端校验 JWT 时会检查aud声明与之一致satisfies AuthConfig让 TypeScript 对配置结构做类型检查。前端认证桥接把 Clerk 的登录态喂给 ConvexConvex 与 Clerk 的集成核心在 src/main.tsx 的 Provider 嵌套结构中共三层ClerkProvider初始化 Clerk 前端 SDK管理登录会话ConvexProviderWithClerk来自convex/react-clerk的桥接 Provider接收两个参数——clientConvexReactClient实例用VITE_CONVEX_URL指向 Convex 部署和useAuthClerk 的useAuthhook。它的职责是把 Clerk 维护的登录态session token自动转交给 Convex 客户端使得之后所有 Convex query / mutation 请求都会携带经过 Clerk 签发的 JWTApp业务根组件。这种嵌套结构意味着前端无需手动把 token 塞进每个请求——只要登录态存在Convex 客户端就会自动附加认证信息登出后token 随之失效后端调用自动回到未认证状态。登录状态驱动的界面切换src/App.tsx 演示了如何用 Clerk 的useAuth钩子驱动整个应用视图import { SignOutButton, useAuth } from clerk/react; import { useMutation, useQuery } from convex/react; import { FormEvent, useState } from react; import { api } from ../convex/_generated/api; import Badge from ./Badge; import LoginPage from ./LoginPage; export default function App() { const { isSignedIn, isLoaded } useAuth(); if (!isLoaded) { return divClerk is loading.../div; } return main{isSignedIn ? Content / : LoginPage /}/main; }逻辑要点isLoaded表示 Clerk 是否已完成会话状态初始化。在加载完成前渲染占位文案Clerk is loading...避免闪屏或错误分支isSignedIn布尔值直接决定渲染Content聊天界面还是LoginPage登录页。未登录一个按钮的登录页src/LoginPage.tsx 极简至极——核心就是一个SignInButtonimport { SignInButton } from clerk/react; export default function LoginPage() { return ( h1Convex Chat/h1 h2 SignInButton / /h2 / ); }SignInButton是 Clerk 提供的现成组件点击后会弹出 Clerk 托管的登录界面支持邮箱、社交登录等取决于你的 Clerk 应用配置无需自己实现登录表单。已登录展示身份 登出 聊天登录后渲染Content组件包含三部分Badgesrc/Badge.tsx通过useUser()获取当前用户信息展示 Logged in as {fullName}import { useUser } from clerk/react; export default function Badge() { const { user } useUser(); return ( p classNamebadge spanLogged in{user!.fullName ? as ${user!.fullName} : }/span /p ); }SignOutButtonClerk 现成的登出按钮点击后清除会话isSignedIn变为false界面自动切回登录页消息列表与发送表单通过 Convex React hooks 与后端函数交互const messages useQuery(api.messages.list) || []; const sendMessage useMutation(api.messages.send); // ... await sendMessage({ body: newMessageText });渲染时每条消息显示author、body和_creationTime转为本地时间字符串。后端函数中的身份校验与数据关联认证的另一半发生在后端。真正的身份校验逻辑在 convex/messages.ts 中核心 API 是ctx.auth.getUserIdentity()import { v } from convex/values; import { mutation, query } from ./_generated/server; export const send mutation({ args: { body: v.string() }, handler: async (ctx, args) { const identity await ctx.auth.getUserIdentity(); if (!identity) { throw new Error(Unauthenticated call to mutation); } await ctx.db.insert(messages, { body: args.body, author: identity.name ?? Unknown, }); }, }); export const list query({ args: {}, handler: async (ctx) { return await ctx.db.query(messages).collect(); }, });这个函数值得逐行解读getUserIdentity()由 Convex 运行时解析请求附带的 JWT并返回经过验证的用户身份对象包含 Clerk 用户信息如name、subject等。它是 Convex 认证机制的核心入口——服务端根据auth.config.ts中配置的 Issuer 和 Audience 校验 token 的签名与声明未认证拦截if (!identity) throw new Error(Unauthenticated call to mutation)。没有有效登录态时mutation 直接抛错拒绝执行防止匿名写入身份落库通过identity.name ?? Unknown把用户显示名写入消息的author字段实现每条消息与发送者关联v.string()参数校验send的body参数声明为字符串Convex 会在执行前做运行时校验。数据模型定义在 convex/schema.tsimport { defineSchema, defineTable } from convex/server; import { v } from convex/values; export default defineSchema({ messages: defineTable({ body: v.string(), author: v.string(), }), });list查询则是公开的任何能访问应用的人都可以读取全部消息无身份过滤这符合聊天室场景——读公开、写受限。关于users 表的说明README 与当前实现的一处差异README 中提到登录后用户信息 persisted to auserstable持久化到users表。但对比当前仓库中的 convex/schema.ts 可以看到当前实现只定义了messages一张表并没有users表。实际的数据关联方式是在每条消息上直接写入author字段用户显示名用户详情仍由 Clerk 侧维护。从源码结构可以推断这是示例为了保持最小化而采用的简化方案真正需要完整用户档案头像、邮箱、自定义属性等时可以在登录后通过 mutation 把getUserIdentity()返回的身份信息同步写入一张users表并建立外键关联。实现时以实际 schema 为准即可。换成你自己的 Clerk 实例完整步骤按 README 的指引把示例接上自己的 Clerk 实例只需三步在 Clerk Dashboard 创建应用并配置 JWT 模板按 Clerk 文档创建应用并为其配置一个用于 Convex 的 JWT 模板从中获得Publishable Keypk_test_...形式的前端密钥JWT Template Issuer URL形如https://your-instance.clerk.accounts.dev的签发者地址。更新前端 src/main.tsx把ClerkProvider的publishableKey替换为你的 Publishable Key。更稳妥的做法是改用环境变量ClerkProvider publishableKey{import.meta.env.VITE_CLERK_PUBLISHABLE_KEY}并在项目根目录的.env.local中配置VITE_CLERK_PUBLISHABLE_KEY...以及已存在的VITE_CONVEX_URL。更新后端 convex/auth.config.ts把providers[0].domain替换为你的 JWT 模板 Issuer URLapplicationID保持与你 JWT 模板中的 Audience 一致示例为convex。同样建议用环境变量区分环境domain: process.env.CLERK_JWT_ISSUER_DOMAIN!,并在 Convex Dashboard 的部署环境变量中配置CLERK_JWT_ISSUER_DOMAIN这样开发与生产实例可以各自指向不同的 Clerk 应用。完成后重新运行npm run dev即得到一套完整可用的「Clerk 登录 → Convex 鉴权 → 身份落库 → 登出」闭环应用。这个示例可以继续向两个方向扩展一是新增users表持久化完整用户档案二是为list查询增加基于身份的消息过滤——后端只要调用ctx.auth.getUserIdentity()即可拿到当前用户扩展点清晰且成本极低。【免费下载链接】convex-backendThe open-source reactive database for app developers项目地址: https://gitcode.com/gh_mirrors/co/convex-backend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表