NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

如何在 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:472331

评论

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

最近被安排搞搜索接口优化,压测了4次,才勉强达到要求

Java 程序员 后端

服了!阿里资深架构师发布SpringCloud笔记,在GitHub标星已达81

Java 程序员 后端

数据库索引的原理,springcloud视频百度云

Java 程序员 后端

数论 - 约数基础 【 试除法求所有约数 + 约数个数和约数之和

Java 程序员 后端

斯坦福高效睡眠法-读书笔记,这可能是目前最全的

Java 程序员 后端

最新版SpringBoot开发实战:阿里技术官从基础到项目综合实战pdf

Java 程序员 后端

月薪60k的Java开发在阿里是什么级别?对技术能力有哪些要求?

Java 程序员 后端

如何用内网渗透突破安全策略

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 安全漏洞

来自北京大学NOIP金牌选手yxc的常用代码模板3——搜索与图论

Java 程序员 后端

数据库ACID四大特性到底为了啥,一文带你看通透,java支付宝支付接口教程

Java 程序员 后端

是什么让普通的链表也能达到二分查找的效率,你知道吗?

Java 程序员 后端

普通本科,毕业六年,复盘一个月,mybatis一级缓存和二级缓存面试题

Java 程序员 后端

普通程序员就不能有拥有架构师光环?想要建立架构思维,这份京东架构技术精髓一定不能错过

Java 程序员 后端

新人问一般都用哪些 Linux 命令,我把这个扔了过去,linux基础及应用教程课后答案

Java 程序员 后端

来自北京大学NOIP金牌选手yxc的常用代码模板4——数学知识

Java 程序员 后端

来自阿里大牛20000字总结-+-40张图文详解,我就不信你还参透不了并发编程

Java 程序员 后端

架构师成长之路-docker 搭建es集群,rocketmq教程教程

Java 程序员 后端

数据结构的栈和队列(这不进来看一看),计算机java语言入门

Java 程序员 后端

本科毕业斩获字节offer的我做了什么准备?大厂面试经验试题分享(1)

Java 程序员 后端

有个厉害的程序员老婆是什么体验?,mysql性能优化面试题

Java 程序员 后端

推荐这款牛掰的 API 敏捷开发工具,java程序设计教程课后题答案

Java 程序员 后端

提升开发效率N倍的20+命令行神器,赶紧收藏了,mybatis原理图

Java 程序员 后端

无论你是什么职业,这篇职场生存法则都是你必备的,java微服务架构技术

Java 程序员 后端

是什么Java面试题PDF被Git全面封杀?刷完这套题已经拿完9个Offer!

Java 程序员 后端

数据源的概念是什么?Springcloud+Mybatis如何使用多数据源

Java 程序员 后端

数据结构系列第六部分:排序,Github爆火的《高并发秒杀顶级教程》

Java 程序员 后端

极速体验docker容器健康,高并发分布式系统架构

Java 程序员 后端

数据库中间件MyCat实战笔记(第一步),arm架构linux系统

Java 程序员 后端

最新基准测试:Kafka、Pulsar-和-RabbitMQ-哪个最快,阿里Java笔试题目

Java 程序员 后端

本科毕业斩获字节offer的我做了什么准备?大厂面试经验试题分享

Java 程序员 后端

Go channel,面试官会这样问

Rayjun

channel Go 语言

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