Clerk 是一个 serverless 登录鉴权服务,支持大量第三方的 OAuth 登录,很方便就能搭建起登录体系,免费额度也较高。结合 Next.js 和 Hono.js 使用可很容易实现前后台全面的鉴权。
Next.js 配置
查看 nextjs 的快速指南:
https://clerk.com/docs/quickstarts/nextjs
npm install @clerk/nextjs
定义环境变量 NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY 和 CLERK_SECRET_KEY
然后使用 ClerkProvider 在 app/layout.tsx 包裹整个应用。
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<ClerkProvider>
<html lang="en">
...
</html>
</ClerkProvider>
)
}
创建登录、导出页
https://clerk.com/docs/references/nextjs/custom-signup-signin-pages
创建 app/sign-in/[[...sign-in]]/page.tsx
导入组件,登出页同理。
import { SignIn } from '@clerk/nextjs'
export default function SignInPage() {
return <SignIn />
}
环境变量配置:
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
用户控件与用户信息
使用用户头像控件:
import { ClerkLoaded, ClerkLoading, UserButton } from "@clerk/nextjs"
<ClerkLoaded>
<UserButton />
</ClerkLoaded>
<ClerkLoading>
<Loader2 className="size-8 animate-spin text-slate-400" />
</ClerkLoading>
获取用户信息:
import { useUser } from '@clerk/nextjs';
const { user, isLoaded } = useUser();
{isLoaded ? user?.firstName : ''}
Next.js 中间件拦截登录
通过 middleware.ts 配置拦截,通过白名单形式控制不拦截的页面:
mport { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
import { NextResponse } from 'next/server'
const isPublicRoute = createRouteMatcher([
'/sign-in(.*)',
'/sign-up(.*)',
'/api/(.*)' //不拦截接口, api 使用 hono.js 中间件控制登录状态
])
export default clerkMiddleware(async (auth, request) => {
if (!isPublicRoute(request)) {
await auth.protect()
}
return NextResponse.next()
})
export const config = {
matcher: [
// Skip Next.js internals and all static files, unless found in search params
'/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',
// Always run for API routes
'/(api|trpc)(.*)',
],
}
Hono.js 结合使用
Hono.js 社区有很多中间件:
https://hono.dev/docs/middleware/third-party
Clerk Auth 中间件:
https://github.com/honojs/middleware/tree/main/packages/clerk-auth
为它配置环境变量 CLERK_PUBLISHABLE_KEY ,也就是把之前的 NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY 复制一份。
可结合一个全局中间件,控制所有接口的登录情况,并统一返回:
app.use('*', clerkMiddleware(), async (c, next) => {
const auth = getAuth(c)
if (!auth?.userId) {
throw new HTTPException(401, {
res: c.json({ error: "未登录" })
})
}
await next()
})
在路由代码中获取用户信息:
import { getAuth } from '@hono/clerk-auth';
const auth = getAuth(c);
console.log(auth.userId)
这样就可以结合 Hono.js 和 Next.js 的登录,达到一体化控制,页面未登录重定向到登录页,接口未登录返回 json 格式。Next Auth 也可以使用类似的配置方式。