2025上半年,最新 AI实践都在这!20+ 应用案例,任听一场议题就值回票价 了解详情
写点什么

如何在 Next.js 全栈应用程序中无缝实现身份验证

作者:Zevi Reinitz

  • 2023-08-21
    北京
  • 本文字数:4456 字

    阅读完需:约 15 分钟

如何在Next.js全栈应用程序中无缝实现身份验证

本教程中,我们将一同了解如何使用 Clerk 向全栈应用程序添加身份验证机制。

 

我们跟 Clerk 没有任何合作关系,但对这款工具的表现非常认可。很多朋友正好咨询怎么在 Next.js 下实现身份验证,这篇文章专为解决问题而来。

 

背景介绍

 

身份验证一直是构建全栈应用程序中的一大主要痛点。特别是在 Node.js 环境当中,各种主流库和框架都没有内置 auth-primitives。因此,开发人员不得不自己想办法构建身份验证解决方案。

 

但从零开始构建安全身份验证是项颇为艰巨的任务。我们首先得对密码进行哈希和加盐处理,发布签名令牌来创建会话,同时防止各种恶意攻击向量。此外,大家还得保证自己的前端和后端能够相互通信、正常共享会话。

 

好消息是,Express 的 Passport.js 和 Next.js 的 NextAuth 等库就是为此而生,只是还不够完美。这些库的设置流程涉及多个步骤,虽然已经能较好地配合 Google 或 GitHub 等服务实现社交身份验证,但毕竟要比密码登录更困难。而且密码内容仍须存储在服务端数据库内,由软件开发一方承担全部安全责任。

 

如今,登录时通过邮件验证、无密码登录和双因素身份验证已经相当流行。虽然前面讨论的库也能支持这些功能,但需要在本就复杂的设置之外再做更多额外工作。

这时就要请出托管身份验证提供程序 Clerk 了,它消除了身份验证中的所有难题,大大降低了妥善保护全栈应用程序的门槛。与其他托管身份验证提供程序相比,Clerk 的开发者体验也明显做得更好。

 

在本教程中,我们将运用 Clerk 及其全新 App Router,在 Next.js 13 当中构建一款简单的全栈应用程序。



设置


首先在您终端中指定的文件夹中运行命令 npx create-next-app@latest,从而创建新的 Next 应用程序。请按以下指定方式完成设置。需要注意的是,一定要在 Tailwind CSS 和 App Router 部分选择 Yes。

 

Desktop npx create-next-app@latest✔ What is your project named? ... clerk-auth✔ Would you like to use TypeScript with this project? ... No / Yes✔ Would you like to use ESLint with this project? ... No / Yes✔ Would you like to use Tailwind CSS with this project? ... No / Yes✔ Would you like to use `src/` directory with this project? ... No / Yes✔ Use App Router (recommended)? ... No / Yes✔ Would you like to customize the default import alias? ... No / Yes
复制代码

 

现在我们切换到刚刚创建的 clerk-auth 文件夹,安装唯一的依赖项:Clerk。

 

npm install @clerk/nextjs
复制代码

 

接下来需要创建一个 Clerk 账户和新项目,获取要用到的 API 密钥。这就需要转到 clerk.com,创建一个账户,之后在仪表板上单击“Add application”。

 

将应用程序命名为 clerk-auth-demo,并选择 Email + Google 的登录方式。如果需要,大家还可以添加其他登录方式。请放心,这不会对开发过程产生任何影响,Clerk 为替我们完成所有工作。



 现在,Clerk 会自动提供要添加到 Next 应用程序的 API 密钥。



 因此,请创建一个.env.local 文件,把 Clerk 那边复制的内容全部粘贴进来。

 

NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_****CLERK_SECRET_KEY=sk_test_******
复制代码

 

要完成 Clerk 身份验证配置,最后一步就是把这款身份验证提供程序添加到/src/app/layout.tsx 文件当中。如果大家比较熟悉传统的 Next.js 页面范式,会发现其内容跟/src/_app.tsx 文件差不多。

 

import { ClerkProvider } from '@clerk/nextjs';import './globals.css';import { Inter } from 'next/font/google';const inter = Inter({ subsets: ['latin'] });export const metadata = {  title: 'Create Next App',  description: 'Generated by create next app',};export default function RootLayout({ children }: { children: React.ReactNode }) {  return (    <ClerkProvider      appearance={{        variables: {          colorPrimary: 'red',        },      }}    >      <html lang="en">        <body className={inter.className}>{children}</body>      </html>    </ClerkProvider>  );}
复制代码

 

ClerkProvider 中提供一项 appearance 属性,我们可以在其中定制 Clerk 组件以匹配应用程序的设计风格。每个 Clerk 组件还能单独设置样式。到这一步,我们就能在应用程序中使用 Clerk 了。

 

向应用添加身份验证

登录和注册页


首先,我们需要创建注册和登录页。Clerk 已经提供了完整的表单组件,剩下要做的就是利用这些组件构建一个简单的示例页面。

 

我们从登录页开始。使用以下内容,在/src/app/sign-in/[[..sign-in]]/page.tsx 中创建一个新组件:import { SignIn } from '@clerk/nextjs';

 

export default function SignInPage() {  return (    <div className="flex items-center justify-center h-screen">      <SignIn />    </div>  );}
复制代码

 

这里的文件路径可能跟大家习惯的传统 Next.js 应用有所区别,其中页面 URL 由/src/app/sign-in 文件夹来定义,代表着页面实际上位于/sign-in。中括号用于捕捉 Clerk 内部使用的/sign-in/... 之后的所有内容。使用新的 App Router 功能,页面本体将始终存放在 page.tsx 文件之内。

 

至于/src/app/sign-up/[[..sign-up]]/page.tsx 注册页面,处理方式也基本相同:import { SignUp } from '@clerk/nextjs';

 

import { SignUp } from '@clerk/nextjs';

export default function SignUpPage() { return ( <div className="flex items-center justify-center h-screen"> <SignUp /> </div> );}
复制代码

 

现在转到 http://localhost:3000/sign-in ,就能看到预制好的注册组件,它支持电子邮件、密码或者大家指定的任何社交身份验证提供程序。



账户页面


创建一个账户,或者通过 Google 进行登录。到这里,我们已经完成了应用登录,但目前的功能还比较有限。所以我们需要创建账户页面,首先将/src/app/page.tsx 文件中的内容变更为:

 

import { UserButton } from '@clerk/nextjs';export default function Home() {  return (    <div className="flex justify-center items-center h-screen">      <div className="bg-white p-4 rounded-md flex items-center gap-4 text-gray-600">        <p>Hello, User!</p>        <UserButton afterSignOutUrl="/" />      </div>    </div>  );}
复制代码

 

这里我们使用到 Clerk 的 UserButton 组件。登录之后,它将为提供 User Setting 的下拉菜单,用户可以在其中更改密码、电子邮件地址和其他各种设置。这些功能是收费的,但毕竟能帮我们省下自行开发验证带来的时间和精力投入。

 

保护页面

Secret 页面

 

现在我们需要在/protectet 上创建一个新页面,要求该页面只能由经过身份验证的用户访问。为此,我们需要在/src/middleware.ts 中创建一个新的中间件,内容如下:

 

import { authMiddleware } from "@clerk/nextjs";export default authMiddleware({  publicRoutes: ["/"]});export const config = {  matcher: ["/((?!.*\\..*|_next).*)", "/", "/(api|trpc)(.*)"],};
复制代码

 

此外,将以下新变更添加到.env.local 文件当中,以告知 Clerk 在需要重新定向时如何操作。

 

// other settingsNEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-inNEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-upNEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
复制代码

 

Clerk 提供的这个中间件,将确保只有 root 页面和注册/登录页面对未经身份验证的用户可见。现在让我们在/src/app/protected/page.tsx 上创建页面:

 

export default function Protected() {  return (    <div className="flex justify-center items-center h-screen">      <div className="bg-white p-4 rounded-md flex items-center gap-4 text-gray-600">        <p>This is a protected page</p>      </div>    </div>  );}
复制代码

 

这样在登录和注销时,就会转向这个页面。请注意,如果未能通过身份验证,访问者将被重新定向至/sign-in。

 

在主页中显示登录链接

 

当用户尚未登录时,我们的 root 页面目前不会显示任何信息。但现在中间件已经设置完毕,我们可以修改/src/app/page.tsx 文件来更改此中间件:

 

import { UserButton, currentUser } from '@clerk/nextjs';import Link from 'next/link';export default async function Home() {  const user = await currentUser();  return (    <div className="flex justify-center items-center h-screen">      <div className="bg-white p-4 rounded-md flex items-center gap-4 text-gray-600">        {user ? (          <>            <p>Hello, User: {user.emailAddresses[0]?.emailAddress}</p>            <UserButton afterSignOutUrl="/" />          </>        ) : (          <Link href="/sign-in" className="text-blue-500">            Sign in          </Link>        )}      </div>    </div>  );}
复制代码

 

这是一个 React 服务器组件,会使用 await 从 Clerk 异步获取当前用户会话。取决于会话是否存在,它会显示 UserButton 以及用户的电子邮件地址,或者指向登录页面的链接。

 

保护 API 路由


到这里,我们已经讨论了如何保护应用前端。但全栈应用程序还有后端部分,为此我们将在新的 App Router 模式中使用/src/app/api/route.ts 文件,借此在 GET/api 处创建一个后端端点:

 

import { auth } from '@clerk/nextjs';import { NextResponse } from 'next/server';export async function GET() {  const { userId } = auth();  if (!userId) {    return new Response('Unauthorized', { status: 401 });  }  const data = { message: 'Hello User', id: userId };  return NextResponse.json({ data });}
复制代码

 

这里的 auth()函数会检查是否存在 Clerk 会话。如果不存在,则抛出 401 未经授权错误。而如果用户成功通过了身份验证,接下来就是设置用户能在端点上进行的操作了。我们可以访问 userId,据此将数据库中的数据引用给用户。

 

总结


至此,我们已经在全栈 Next.js 13 应用程序中完成了 Clerk Authentication 的完整实施。可以看到,整个过程几乎无需编写任何身份验证代码就能正常起效!这也是 Clerk 等外部提供程序的魅力所在。更重要的是,我们的小小演示应用也内置了一系列用户管理功能,包括验证/更改电子邮件地址、更改密码和社交登录等,能帮开发者省下很多时间。

 

对于同时拥有前端和后端的全栈应用程序,Clerk 在 Next.js 等框架中有着相当出彩的表现。但如果匹配单独的后端,那在设置方面就要更复杂一些。Clerk 可以发出 JWT 令牌,由开发者将其与 API 请求一同发往后端以验证用户身份。这种方式虽然可行,但整个过程肯定不如本文展示的那样无缝丝滑。

 

原文链接:


https://dev.to/livecycle/seamless-full-stack-authentication-in-nextjs-11lp


相关阅读:


为什么说 Next.js 13 是一个颠覆性版本

Next.js 实践:从 SSR 到 CSR 的优雅降级

Next.js 13 新的实验性特性,实现 App“动态无限制”

我们如何使用 Next.js 将 React 加载时间缩短 70%

2023-08-21 11:473833

评论

发布
暂无评论
发现更多内容

大模型时代,企业如何重构 AI 应用落地范式?

Fabarta

用于提取数据的三个开源NLP工具

互联网工科生

nlp NLP 大模型

听说 Spring Bean 的创建还有一条捷径?

江南一点雨

spring

对线面试官 - HashMap

派大星

HashMap底层原理 Java 面试题

人人都有大模型用!大模型ChatGLM2-6B新手速通!

飞桨PaddlePaddle

人工智能 百度 paddle 飞桨 百度飞桨

软件测试/测试开发丨Python 内置库 文件处理 学习笔记分享

测试人

Python 程序员 软件测试 文件处理 内置库

Java学习13:static关键字,this关键字

java易二三

Java 编程 程序员 计算机

三连冠!天翼云蝉联中国专属云服务市场第一

天翼云开发者社区

云计算 云服务

英伟达 H100 vs. 苹果M2,大模型训练,哪款性价比更高?

GPU算力

Spring高手之路10——解锁Spring组件扫描的新视角

砖业洋__

spring @Component 包扫描 bean的默认名称

企业全面预算管理的生存指南:建立成功的FP&A团队

智达方通

全面预算管理 企业全面预算管理 财务规划与分析 财务数据

大数据通用组件故障处理

天翼云开发者社区

大数据

HPC云化部署的优势和挑战

天翼云开发者社区

云计算 高性能计算

腾讯云 CODING 成为首批 TISC 企业级平台工程综合能力要求标准贡献单位

CODING DevOps

JMeter 查看 TPS 数据

Liam

程序员 测试 Jmeter 测试工具 TPS

国内常见的16款低代码开发平台介绍

优秀

低代码开发平台 低代码平台 企业级低代码平台

全球视频编码领域顶级大赛放榜,网易云信首次参赛即斩获H.265赛道多项指标第一

网易智企

音视频技术 H.265

信创产业未来发展如何

小齐写代码

【我和openGauss的故事】openGauss价值特性 (二)

daydayup

Flink 实践教程:入门(11):MongoDB Sink 的使用

腾讯云大数据

流计算 Oceanus

新鲜出炉!Go薪资最高,JS需求量最大!

树上有只程序猿

Java c++ Python 编程语言

低代码:告别繁琐,提速软件开发

互联网工科生

软件开发 低代码 数字化

语雀 × 支付宝小程序云:发布技术干货,赢语雀会员和周边!

TRaaS

文档写作 #程序员

IDC公布2022中国大数据平台私有化部署市场份额,柏睿数据位列第一梯队

新消费日报

ChatGPT下程序员应该何去何从?

小齐写代码

全球视频编码领域顶级大赛放榜,网易云信首次参赛即斩获H.265赛道多项指标第一

网易云信

音视频 H.265 音视频通话

AI算力爆发,新职业出现,你发现了吗?

小齐写代码

新版安卓iOS双端语音派对聊天APP源码开发核心功能和开发要点介绍

山东布谷科技胡月

语音聊天APP源码 视频语音直播app开发 语音社交APP搭建 语音房APP开发 语音厅源码

如何在Next.js全栈应用程序中无缝实现身份验证_工程化_InfoQ精选文章