尧图精选

SpacetimeDB 接入 Clerk 认证实战:从 JWT 获取到 React 客户端连接的全流程指南

🕒 发布时间:2026/9/12 22:14:24 📁 来源:尧图网络
SpacetimeDB 接入 Clerk 认证实战从 JWT 获取到 React 客户端连接的全流程指南【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB本篇指南完整讲解如何将Clerk托管式身份认证服务与SpacetimeDBReact 应用集成先在 Clerk 控制台配置应用并获取 Publishable Key然后在浏览器中从 Clerk 会话获取 JWT 作为认证令牌最终通过DbConnection.builder().withToken(...)将令牌传给 SpacetimeDB 连接实现服务端的令牌校验与身份识别。读完本文你将掌握一套可复制的第三方 OIDC 身份提供商 → React 客户端 → SpacetimeDB 模块的认证接入方案并能基于仓库源码理解其底层实现。前置条件在开始前请确保以下条件已就绪一个可运行的 SpacetimeDB 项目可参照 React Quickstart 中spacetime dev --template react-ts的方式快速创建一个同时包含 SpacetimeDB 模块与 React 客户端的项目。该模板会启动本地 SpacetimeDB 服务器、发布模块、生成 TypeScript 绑定并启动 React 开发服务器默认地址http://localhost:5173。一个 Clerk 账号用于在 Clerk Dashboard 创建应用、获取密钥。整体架构Clerk 令牌如何进入 SpacetimeDB 连接在深入步骤之前先理清这条认证链路的数据流用户在浏览器中访问你的 React 应用ClerkProvider管理全局认证状态未登录用户被RedirectToSignIn重定向到 Clerk 的登录界面登录成功后useAuth().getToken()在浏览器中返回由 Clerk 签发的会话令牌JWT该 JWT 通过 React Context 暴露给应用组件组件将其传给DbConnection.builder().withToken(token)SpacetimeDB 客户端在建立连接时把令牌作为 bearer token 随握手消息发送服务端校验其签名与 claims并把subiss映射为该用户的Identity。其中第 4 步是核心SDK 中DbConnectionBuilder.withToken的实现见 db_connection_builder.ts将令牌保存在 builder 内部状态随后建立连接时携带该凭据。onConnect回调返回的identity即为服务端基于 JWT 的sub/iss计算出的用户身份。分步实施第 1 步安装 Clerk React SDK在 React 应用目录中使用任意你惯用的包管理器安装clerk/clerk-reactnpm add clerk/clerk-reactyarn add clerk/clerk-reactpnpm add clerk/clerk-reactbun add clerk/clerk-react第 2 步配置 Clerk 应用进入Clerk Dashboard创建或选择一个 Application在应用设置中找到Publishable key并妥善保存——稍后需要在main.tsx中使用确保你的本地开发地址被 Clerk 允许例如使用 Vite 时填入http://localhost:5173准备一个由 Clerk 签发的JWT用于发送给 SpacetimeDB。Clerk 通过会话令牌session token签发 JWT后续步骤中我们会在浏览器中从当前会话取出该令牌。说明Clerk 签发的是符合 OIDC 规范的 JWTSpacetimeDB 服务端可以解析其中的sub用户唯一标识、iss签发者、aud受众等标准 claims 来计算用户Identity并执行鉴权。第 3 步创建 ClerkTokenProvider 组件新建ClerkTokenProvider.tsx该组件需要完成三件事确保用户已登录未登录时重定向到 Clerk 的登录 UI登录后从 Clerk 获取会话令牌JWT通过 React Context 将令牌暴露给应用模式与 Auth0 教程中的AutoLogin组件类似可对照 Auth0 集成指南 理解这一模式的通用性。import React, { createContext, useContext, useEffect, useMemo, useState, } from react; import { useAuth, RedirectToSignIn } from clerk/clerk-react; const TokenContext createContextstring | undefined(undefined); export function useClerkToken() { const token useContext(TokenContext); if (!token) { throw new Error(useClerkToken must be used within a ClerkTokenProvider); } return token; } /** * ClerkTokenProvider: * - If signed out: renders Clerks redirect component. * - If signed in: loads a Clerk session token (JWT) and provides it via context. * * Note: * - getToken() returns a token suitable for sending to your backend. If you have * configured a specific JWT template in Clerk, pass its name via * getToken({ template: YOUR_TEMPLATE_NAME }). */ export function ClerkTokenProvider({ children, }: { children: React.ReactNode; }) { const { isLoaded, isSignedIn, getToken } useAuth(); const [token, setToken] useStatestring | null(null); const [error, setError] useStateError | null(null); useEffect(() { let cancelled false; async function run() { if (!isLoaded) return; // IMPORTANT: if signed out, clear any cached token if (!isSignedIn) { if (!cancelled) setToken(null); return; } try { // If you use a Clerk JWT template, use: // const t await getToken({ template: YOUR_TEMPLATE_NAME }); const t await getToken(); if (!t) { throw new Error(Clerk returned no session token.); } if (!cancelled) setToken(t); } catch (e) { if (!cancelled) setError(e as Error); } } run(); return () { cancelled true; }; }, [isLoaded, isSignedIn, getToken]); const value useMemostring | undefined(() token ?? undefined, [token]); if (error) { return ( div pAuthentication error/p pre{error.message}/pre /div ); } if (!isLoaded) { return pLoading.../p; } if (!isSignedIn) { // Sends the user to Clerk sign-in. After sign-in, they return to the app. return RedirectToSignIn /; } if (!token) { return pLoading.../p; } return ( TokenContext.Provider value{value}{children}/TokenContext.Provider ); }实现要点解读useAuth()来自clerk/clerk-react提供isLoadedClerk 初始化完成状态、isSignedIn登录状态与getToken异步获取会话令牌useEffect内部用cancelled标志位防止组件卸载后异步回调更新状态React StrictMode 下尤其重要见下方main.tsx中的StrictMode包裹登出时立即清空缓存令牌避免旧凭证被误用令牌通过TokenContext.Provider下发useClerkTokenhook 在 Provider 外使用时会抛出明确错误便于快速定位错误用法。第 4 步在 main.tsx 中用 ClerkProvider 包裹应用修改main.tsx用ClerkProvider包裹整个应用让 Clerk 管理认证状态并把ClerkTokenProvider放在其内部import { StrictMode } from react; import { createRoot } from react-dom/client; import { ClerkProvider } from clerk/clerk-react; import App from ./App.tsx; import { ClerkTokenProvider } from ./ClerkTokenProvider.tsx; createRoot(document.getElementById(root)!).render( StrictMode ClerkProvider publishableKeyYOUR_CLERK_PUBLISHABLE_KEY ClerkTokenProvider App / /ClerkTokenProvider /ClerkProvider /StrictMode );将YOUR_CLERK_PUBLISHABLE_KEY替换为第 2 步保存的Publishable Key。层级关系为ClerkProvider全局认证上下文→ClerkTokenProvider令牌获取与下发→App业务组件。第 5 步更新 App.tsx 使用 Clerk 令牌在App.tsx中读取 Clerk 令牌并将其传入DbConnection构建器。这与 Auth0 流程一致SpacetimeDB 收到 bearer tokenJWT并在服务端校验。import { useMemo } from react; import { Identity } from spacetimedb; import { SpacetimeDBProvider } from spacetimedb/react; import { DbConnection, ErrorContext } from ./module_bindings; import { useClerkToken } from ./ClerkTokenProvider; const onConnect (_conn: DbConnection, identity: Identity) { console.log( Connected to SpacetimeDB with identity:, identity.toHexString() ); }; const onDisconnect () { console.log(Disconnected from SpacetimeDB); }; const onConnectError (_ctx: ErrorContext, err: Error) { console.log(Error connecting to SpacetimeDB:, err); }; export default function App() { const token useClerkToken(); const connectionBuilder useMemo(() { return DbConnection.builder() .withUri(YOUR SPACETIMEDB URL) .withDatabaseName(YOUR SPACETIMEDB MODULE NAME) .withToken(token) .onConnect(onConnect) .onDisconnect(onDisconnect) .onConnectError(onConnectError); }, [token]); return ( SpacetimeDBProvider connectionBuilder{connectionBuilder} div h1SpacetimeDB React App/h1 p You can now use SpacetimeDB in your app with Clerk authentication! /p /div /SpacetimeDBProvider ); }配置项说明对照 db_connection_builder.tsBuilder 方法作用取值示例.withUri(...)SpacetimeDB 服务器地址本地开发ws://localhost:3000或云端部署地址.withDatabaseName(...)目标数据库模块名称模板生成的数据库名.withToken(token)连接凭据即 Clerk 签发的 JWT可选但本教程必填useClerkToken()的返回值.onConnect(cb)连接成功后回调参数含identity基于 JWT 的sub/iss计算打印identity.toHexString().onDisconnect(cb)断开连接回调打印日志.onConnectError(cb)连接错误回调可用于展示认证失败信息打印err.message注意useMemo的依赖数组为[token]当用户登录态变化导致令牌更新时connectionBuilder会被重建SDK 会据此用新令牌重建连接。从源码结构看SDK 的 connection_manager.ts 支持用携带新令牌的 builder 替换当前连接的模式这正是实现匿名会话切换为已登录会话或不同用户间切换的机制。第 6 步可选添加基础登录 UI 与登出入口如需快速获得界面控件Clerk 提供了现成的UserButton组件开箱即用地展示用户头像与登出菜单import { UserButton } from clerk/clerk-react; export function Header() { return ( header style{{ display: flex, justifyContent: flex-end, padding: 12 }} UserButton / /header ); }服务端视角在模块中校验与使用 JWT claims客户端把 Clerk 令牌交给 SpacetimeDB 后服务端模块在 reducer 中可通过ReducerContext访问 JWT 中的认证 claims。SpacetimeDB 对 OIDC 兼容 JWT 提供了标准解析见 Auth Claims 使用指南最常用的是sub与iss#[reducer(client_connected)] pub fn connect(ctx: ReducerContext) - Result(), String { let auth_ctx ctx.sender_auth(); let (subject, issuer) match auth_ctx.jwt() { Some(claims) (claims.subject().to_string(), claims.issuer().to_string()), None { return Err(Client connected without JWT.to_string()); } }; log::info!(sub: {}, iss: {}, subject, issuer); Ok(()) }由于任何持有合法令牌的客户端都能尝试连接官方建议至少校验iss签发者并检查aud受众确保令牌确实面向你的应用签发防止其他应用获得的令牌被重放。Clerk 场景下iss形如https://your-clerk-domainaud则来自 Clerk 应用的 JWT 配置。若使用Clerk JWT 模板控制 claims/audience/issuer服务端校验逻辑需要与之对齐。进阶使用 Clerk JWT 模板控制令牌内容默认情况下getToken()返回 Clerk 为你的应用签发的标准会话令牌。Clerk 的JWT 模板JWT Templates允许你自定义令牌的 claims、受众audience与签发者issuer这是官方推荐的做法因为你可以将aud设置为你的应用标识便于 SpacetimeDB 服务端做受众校验注入自定义 claims如roles、tenant等业务字段在服务端直接读取使用。启用模板后将令牌获取行改为await getToken({ template: YOUR_TEMPLATE_NAME });同时确保 SpacetimeDB 服务端认证层校验对应的签发者issuer与签名密钥。自定义 claims 在服务端的读取方式可参考 Auth Claims 使用指南 中访问自定义 claims一节——例如解析raw_payload中的roles数组实现管理员权限校验。常见问题排查现象可能原因排查方向一直停留在 Loading...isLoaded未就绪或getToken()返回空确认ClerkProvider的publishableKey正确检查浏览器控制台 Clerk 相关报错无限重定向到 Clerk 登录页本地 URL 未被 Clerk 允许在 Clerk Dashboard 的允许来源中确认http://localhost:5173已配置连接时报onConnectError令牌无效、过期或服务端校验失败检查令牌是否过期Clerk 会话令牌默认有时效需处理静默刷新核对服务端 issuer/audience 校验规则登录态切换后身份仍是旧的令牌未触发 builder 重建确认useMemo依赖包含token且ClerkTokenProvider在登出时正确清空令牌总结至此你已完成 Clerk 认证与 SpacetimeDB React 应用的完整对接用户访问应用时会被引导到 Clerk 完成登录浏览器端获取会话 JWT 后通过withToken传入DbConnection构建器SpacetimeDB 服务端解析 JWT 的 claims 并据此计算用户Identity与执行鉴权。这一第三方 OIDC 提供商签发 JWT → React 客户端透传令牌 → SpacetimeDB 服务端校验的接入范式同样适用于 Auth0见 Auth0 集成指南与 SpacetimeDB 官方的 SpacetimeAuth OIDC 方案见 SpacetimeAuth React 集成。进一步了解 JWT claims 在模块内的完整用法与安全最佳实践请继续阅读 Auth Claims 使用指南。【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联 返回资讯列表 →