网易首页 > 网易号 > 正文 申请入驻

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

0
分享至

作者 | Zevi Reinitz

译者 | 核子可乐

策划 | 丁晓昀

本教程中,我们将一同了解如何使用 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 (appearance={{variables: {colorPrimary: 'red',},{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>

这里的文件路径可能跟大家习惯的传统 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>

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

账户页面

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


import { UserButton } from '@clerk/nextjs';export default function Home() {return (

Hello, User!p>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 (

This is a protected pagep>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 (

{user ? (

Hello, User: {user.emailAddresses[0]?.emailAddress}p>) : (Sign inLink>)}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 是一个颠覆性版本 (https://www.infoq.cn/article/VbDui4DRa2Lhq3h0ad2Z )

Next.js 实践:从 SSR 到 CSR 的优雅降级 (https://xie.infoq.cn/article/93e23e080e828a8989a57a622 )

Next.js 13 新的实验性特性,实现 App“动态无限制”(https://www.infoq.cn/article/sITi66wc3mvcNs3PeRkb)

我们如何使用 Next.js 将 React 加载时间缩短 70%(https://www.infoq.cn/article/9G0lBWi2W58114ggfyge )

声明:本文由 InfoQ 翻译,未经许可禁止转载。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
轮到犹太人了!250枚火箭弹突袭以色列,数十万人半夜逃亡

轮到犹太人了!250枚火箭弹突袭以色列,数十万人半夜逃亡

王子看台海
2024-06-19 10:33:08
富士康转移到印度,结果河南这边举步维艰,说明了什么?

富士康转移到印度,结果河南这边举步维艰,说明了什么?

创作者朱海平
2024-06-17 12:03:15
面具下的普京,20年来对乌克兰干了什么?

面具下的普京,20年来对乌克兰干了什么?

史政先锋
2024-06-13 15:31:40
英格兰内讧升级!英超mvp不满1.8亿巨星,名宿调解,凯恩成牺牲品

英格兰内讧升级!英超mvp不满1.8亿巨星,名宿调解,凯恩成牺牲品

阿泰希特
2024-06-19 11:49:54
京东:2024年618成交额、订单量创新高,直播订单量同比增超200%

京东:2024年618成交额、订单量创新高,直播订单量同比增超200%

界面新闻
2024-06-19 07:30:45
刚刚!国家队抄底了!

刚刚!国家队抄底了!

中国基金报
2024-06-19 14:33:13
国产002航母锈迹斑斑,还没服役就破烂不堪?专家给出解释

国产002航母锈迹斑斑,还没服役就破烂不堪?专家给出解释

零点历史说
2024-06-07 11:47:30
张学友演唱会被投诉唱粤语歌!本尊回应:国语还行但自己来自香港

张学友演唱会被投诉唱粤语歌!本尊回应:国语还行但自己来自香港

娱乐白名单
2024-06-18 10:09:38
就在刚刚,中方正式下达“逐客令”,要求这国4天内必须离华!

就在刚刚,中方正式下达“逐客令”,要求这国4天内必须离华!

小乐讲故事
2023-05-17 09:52:08
抗日神剧八路军的伙食,不是海鲜就是法国菜,主打的就是一个上流

抗日神剧八路军的伙食,不是海鲜就是法国菜,主打的就是一个上流

附允历史观
2024-06-19 16:45:10
无敌太阳目前还欠蒙蒂2年1400万 活塞又给蒙蒂加了5年6500万

无敌太阳目前还欠蒙蒂2年1400万 活塞又给蒙蒂加了5年6500万

直播吧
2024-06-19 22:10:18
昔日“彩电大王”走向没落,被美公司欠款40亿,如今沦为三线品牌

昔日“彩电大王”走向没落,被美公司欠款40亿,如今沦为三线品牌

李哥三观很正
2024-06-14 17:51:29
湖南警局“女虎”凌娅,真不是一般的“好色”!

湖南警局“女虎”凌娅,真不是一般的“好色”!

据说说娱乐
2024-06-20 07:55:06
西方意识到可怕后果,只要中国愿意,美军可能连仗都打不下去?

西方意识到可怕后果,只要中国愿意,美军可能连仗都打不下去?

青年的背包
2024-06-19 18:59:49
扎心了!山东34岁大龄剩女相亲看中年薪50万上海剩男,被嫌弃太老

扎心了!山东34岁大龄剩女相亲看中年薪50万上海剩男,被嫌弃太老

四象八卦
2024-06-15 02:01:53
知名品牌被传倒闭,公司辟谣:没有!员工:深圳办公基地被卖了,部分人被“卖给”新公司,另一部分人“停工停产”

知名品牌被传倒闭,公司辟谣:没有!员工:深圳办公基地被卖了,部分人被“卖给”新公司,另一部分人“停工停产”

每日经济新闻
2024-06-19 21:30:08
新加坡媒体:风潮渐退,桑尼椰浆饭摊位已恢复平静

新加坡媒体:风潮渐退,桑尼椰浆饭摊位已恢复平静

直播吧
2024-06-19 22:10:17
实话让你不爽,但能避免无知买单

实话让你不爽,但能避免无知买单

吴女士
2024-06-13 12:41:01
为什么我妈妈瞧不起我爸爸? 看网友的评论引起万千共鸣!

为什么我妈妈瞧不起我爸爸? 看网友的评论引起万千共鸣!

娱乐洞察点点
2024-06-19 07:42:08
少拿1年5500万西亚卡姆的4年1.895亿顶薪合同没有球员选项

少拿1年5500万西亚卡姆的4年1.895亿顶薪合同没有球员选项

直播吧
2024-06-20 10:48:09
2024-06-20 11:06:44
InfoQ
InfoQ
有内容的技术社区媒体
9918文章数 50109关注度
往期回顾 全部

科技要闻

苹果回应AI仅限iPhone15Pro:不是为卖新机

头条要闻

环球:《我的阿勒泰》火到国外 西方媒体破防了

头条要闻

环球:《我的阿勒泰》火到国外 西方媒体破防了

体育要闻

绿军的真老大,开始备战下赛季了

娱乐要闻

黄一鸣“杀疯了” 直播间卖大葱养孩子

财经要闻

茅台大跌,谁的锅?

汽车要闻

售价11.79-14.39万元 新一代哈弗H6正式上市

态度原创

时尚
游戏
本地
公开课
军事航空

“T恤”作为夏季的基础款,竟然有这么多种穿法

高手福利散人福音,梦幻西游全民PK赛终于有“单挑组”了!

本地新闻

中式沙拉宇宙的天花板,它必须有姓名

公开课

近视只是视力差?小心并发症

军事要闻

以色列涉嫌在加沙使用重型炸弹 或多次违反战争法

无障碍浏览 进入关怀版