
关于
Clerk 认证实现的专家模式,涵盖中间件、会话管理和用户认证流程。
name: clerk-auth description: Clerk 认证实现的专家模式,包括中间件、组织、Webhook 和用户同步 risk: safe source: vibeship-spawner-skills (Apache 2.0) date_added: 2026-02-27
Clerk 认证
Clerk 认证实现的专家模式,包括中间件、组织、Webhook 和用户同步
模式
Next.js App Router 设置
完整的 Next.js 14/15 App Router Clerk 设置。
包含 ClerkProvider、环境变量和基本的登录/注册组件。
关键组件:
- ClerkProvider:为应用提供认证上下文
- <SignIn />、<SignUp />:预构建的认证表单
- <UserButton />:带会话管理的用户菜单
代码示例
# 环境变量 (.env.local)
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/dashboard
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/onboarding
// app/layout.tsx
import { ClerkProvider } from '@clerk/nextjs';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<ClerkProvider>
<html lang="en">
<body>{children}</body>
</html>
</ClerkProvider>
);
}
// app/sign-in/[[...sign-in]]/page.tsx
import { SignIn } from '@clerk/nextjs';
export default function SignInPage() {
return (
<div className="flex justify-center items-center min-h-screen">
<SignIn />
</div>
);
}
// app/sign-up/[[...sign-up]]/page.tsx
import { SignUp } from '@clerk/nextjs';
export default function SignUpPage() {
return (
<div className="flex justify-center items-center min-h-screen">
<SignUp />
</div>
);
}
// components/Header.tsx
import { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/nextjs';
export function Header() {
return (
<header className="flex justify-between p-4">
<h1>My App</h1>
<SignedOut>
<SignInButton />
</SignedOut>
<SignedIn>
<UserButton afterSignOutUrl="/" />
</SignedIn>
</header>
);
}
反模式
- 模式:将 ClerkProvider 放在页面组件内 | 原因:Provider 必须在根布局中包裹整个应用 | 修复:将 ClerkProvider 移到 app/layout.tsx
- 模式:不配置中间件就使用 auth() | 原因:auth() 需要配置 clerkMiddleware | 修复:在 middleware.ts 中设置 clerkMiddleware
参考资料
- https://clerk.com/docs/nextjs/getting-started/quickstart
中间件路由保护
使用 clerkMiddleware 和 createRouteMatcher 保护路由。
最佳实践:
- 项目根目录下单个 middleware.ts 文件
- 使用 createRouteMatcher 进行路由分组
- auth.protect() 用于显式保护
- 在中间件中集中所有认证逻辑
代码示例
// middleware.ts
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
// 定义受保护的路由模式
const isProtectedRoute = createRouteMatcher([
'/dashboard(.*)',
'/settings(.*)',
'/api/private(.*)',
]);
// 定义公开路由(可选,为了清晰)
const isPublicRoute = createRouteMatcher([
'/',
'/sign-in(.*)',
'/sign-up(.*)',
'/api/webhooks(.*)',
]);
export default clerkMiddleware(async (auth, req) => {
// 保护匹配的路由
if (isProtectedRoute(req)) {
await auth.protect();
}
});
export const config = {
matcher: [
// 匹配除静态文件外的所有路由
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// 始终对 API 路由运行
'/(api|trpc)(.*)',
],
};
// 高级:基于角色的保护
export default clerkMiddleware(async (auth, req) => {
if (isProtectedRoute(req)) {
await auth.protect();
}
// 管理员路由需要管理员角色
if (req.nextUrl.pathname.startsWith('/admin')) {
await auth.protect({
role: 'org:admin',
});
}
// 高级路由需要高级权限
if (req.nextUrl.pathname.startsWith('/premium')) {
await auth.protect({
permission: 'org:premium:access',
});
}
});
反模式
- 模式:多个 middleware.ts 文件 | 原因:导致冲突和重定向循环 | 修复:使用单个 middleware.ts 配合路由匹配器
- 模式:在组件中手动重定向 | 原因:双重重定向,遗漏路由 | 修复:在中间件中处理所有重定向
- 模式:缺少 matcher 配置 | 原因:中间件不会在所有路由上运行 | 修复:添加全面的 matcher 模式
参考资料
- https://clerk.com/docs/reference/nextjs/clerk-middleware
服务端组件认证
使用 auth() 和 currentUser() 在服务端组件中访问认证状态。
关键函数:
- auth():返回 userId、sessionId、orgId、claims
- currentUser():返回完整的 User 对象
- 两者都需要配置 clerkMiddleware
代码示例
// app/dashboard/page.tsx(服务端组件)
import { auth, currentUser } from '@clerk/nextjs/server';
import { redirect } from 'next/navigation';
兼容工具
Claude CodeCursor
标签
前端开发