
在过去几年中,为应用程序添加身份验证功能已经从晦涩难懂的复杂功能变成了只需使用 API 即可实现的功能。
关于如何在 中实现特定身份验证方案的示例软件仓库和教程并不缺乏,但关于为什么要选择哪些方案、工具和权衡的内容却较少。
本篇文章将介绍在 Next.js 中进行身份验证时需要考虑的事项,从选择提供商到构建登录路由,以及在服务器端和客户端之间做出选择。
基本上有 1000 种 *** 可以在应用程序中建立身份验证。与其在这里关注特定的提供商(这是另一篇博文的主题),不如让我们来看看认证解决方案的类型以及每种解决方案的几个示例。在实施方面, 正迅速成为将 Next.js 应用程序与多个提供商集成、添加 SSO 等功能的热门选择。
这种 *** 非常简单:将用户名和密码存储在关系数据库中。当用户首次注册时,您会在 “users” 表中插入一行新记录,其中包含所提供的信息。当用户登录时,将根据表中存储的信息检查其证书。当用户要更改密码时,就需要更新表中的值。
纵观现有的所有应用程序,传统的数据库验证无疑是更流行的验证方案,而且基本上一直存在。它非常灵活、便宜,而且不会将你锁定在任何特定的供应商。但你确实需要自己构建它,尤其要担心加密问题,并确保那些可爱的密码不会落入坏人之手。
在过去几年里(Firebase 的功劳不只几年前),托管数据库提供商提供某种托管身份验证解决方案已成为相对标准的做法。、 和 都通过一套 API 提供托管数据库和托管身份验证服务,这套 API 可以轻松抽象用户创建和会话管理(稍后详述)。
使用 Supabase 身份验证登录用户:
async function signInWithEmail() {
const { data, error } = await supabase.auth.signInWithPassword({
email: 'example@email.com',
password: 'example-password',
})
}
也许比 DBaaS 提供的身份验证服务更常见的是整个公司或产品提供的身份验证服务。 早在 2013 年就已出现(现在归 Okta 所有),最近又增加了 等产品,这些产品都优先考虑开发人员的体验,并获得了一定的市场份额。

Auth0 用于身份验证
单点登录让你可以将身份 “外包 “给外部提供商,外部提供商可以是像 这样注重安全的企业级供应商,也可以是像 或 GitHub 这样更广泛采用的供应商。Google SSO 在 SaaS 领域无处不在,而一些以开发人员为重点的工具只能通过 GitHub 进行身份验证。
无论你选择哪种供应商,SSO 通常都是上述其他类型身份验证的附加组件,在与外部平台集成方面有(警告:SAML 使用 XML)。
这里没有 “正确 “的选择–什么适合你的项目取决于你的优先事项。如果您希望快速开展工作,而不需要大量的前期配置,那么将认证外包(甚至将包括用户界面在内的全部工作外包给 Auth0 这样的公司)是合理的。如果您预计会有更复杂的设置,那么建立自己的验证后端是合理的。如果你希望支持更大的客户,就需要在某些时候添加 SSO。
Next.js 目前非常流行,大多数身份验证提供商都有 Next.js 专用文档和集成指南。
一些身份验证提供商(如 Auth0)实际上提供了用于注册和登录的整个托管网页。但是,如果你要从头开始创建这些页面,我发现在创建过程中尽早创建这些页面是非常有用的,因为当你真正实施身份验证时,你需要这些页面作为重定向。
因此,先创建这些页面的结构,然后再将请求添加到后台,这样做才有意义。实现身份验证的最直接 *** 就是拥有两个这样的路由:
除了基本功能外,您还需要处理边缘情况,例如用户忘记密码时。有些团队喜欢在单独的路径上设置密码重置流程,而有些团队则喜欢在常规登录页面上添加动态用户界面元素。
一个漂亮的注册页面可能并不意味着成功与失败的区别,但一些小细节却能给人留下好印象,并在整体上提供更好的用户体验。以下是从 *** 上一些网站整理出来的,它们在认证流程中加入了一些额外的爱。
Stripe 导航栏中的行动号召会根据您是否有认证会话而改变。下面是未通过身份验证时营销网站的样子。请注意登录的操作提示:

Stripe 主页会根据您是否通过身份验证来更改 CTA
下面是通过身份验证后的页面。请注意,行动呼吁会将用户带到仪表板,而不是登录:

Stripe 主页更改
虽然没有从根本上改变我的 Stripe 体验,但还是不错的。
一个有趣的技术问题:大多数公司都不会让营销网站的导航栏 “依赖” 身份验证,这是有原因的,因为这意味着每次页面加载时都要额外请求 API 检查身份验证状态,而大多数页面的访问者可能都没有通过身份验证。
在过去几年中,尤其是在 SaaS 领域,公司开始在注册页面添加内容,以 “鼓励” 用户完成注册。这有助于提高页面的转化率,至少可以逐步提高。
下面是 Retool 的一个注册页面,边上有一个动画和一些标识:

如果要这样做,请确保两侧的字体相匹配。
这些额外的小内容可以帮助提醒用户注册的目的以及为什么需要注册。
我可以肯定地说,密码本身就不安全,这是开发人员的常识,但这并不是所有注册你产品的人的常识。鼓励用户创建安全密码对你和他们都有好处。
Coinbase 对注册要求非常严格,要求你使用比名字更复杂的安全密码:

Coinbase 上的弱密码
用密码管理器生成一个密码后,我就可以使用了:

Coinbase 上的强密码
不过,用户界面并没有告诉我密码不够安全的原因,也没有告诉我除了数字之外的其他要求。在产品文案中加入这些要求,会让用户使用起来更顺畅,也有助于避免重试密码时的挫败感。
配合默契每三个美国人中就有一个使用(如 ),但网上仍有许多表单忽略了 HTML 输入中的 `type=` 字样。:
这可以让您在 10 秒钟内顺利完成登录,也可以让您手动完成登录,尤其是在移动设备上。
用户通过身份验证后,您需要选择一种策略来在后续请求中保持该状态。HTTP 是无状态的,我们当然不想在每次请求时都要求用户提供密码。目前有 – 会话(或 Cookie)和 JWTs( *** ON *** 令牌),它们的区别在于由服务器还是客户端来完成这项工作。
在基于会话的身份验证中,维护身份验证的逻辑和工作由服务器处理。基本流程如下:
在会话持续多长时间、何时撤销会话等方面,这种 *** 非常简单,而且可以调整。其缺点是,由于要对数据库进行大量写入和读取,因此会有很大的延迟,但这对大多数读者来说可能不是主要的考虑因素。
不需要在服务器上处理后续请求的身份验证,而是可以在客户端处理(大部分)。工作原理如下:
将初始验证后的所有工作都卸载到客户端后,应用程序的加载和运行速度都会大大加快。但有一个主要问题:服务器无法使 JWT 失效。如果用户想注销设备或其授权范围发生变化,就需要等到 JWT 失效。
Next.js 的部分优势在于内置的静态渲染功能–如果你的页面是静态的,即不需要调用任何外部 API,Next.js 就会自动对其进行缓存,并通过 CDN 以极快的速度提供服务。如果文件中不包含任何 `getServerSideProps` 或 `getInitialProps` 内容,Next.js 13 之前的版本就会知道页面是否是静态的,而 Next.js 13 之后的版本则会使用 来实现这一功能。
对于身份验证,你:渲染一个静态的 “加载” 页面并在客户端执行获取操作,或者在服务器端执行所有操作。对于需要身份验证的页面,你可以呈现一个静态的 “骨架”,然后在客户端发出身份验证请求。理论上,这意味着即使初始内容尚未完全就绪,页面加载速度也会更快。
下面是文档中的一个简化示例,只要用户对象尚未就绪,就会呈现加载状态:
import useUser from '../lib/useUser'
const Profile = () => {
// Fetch the user client-side
const { user } = useUser({ redirectTo: '/login' })
// Server-render loading state
if (!user || user.isLoggedIn === false) {
// Build some sort of loading page here
return <div>Loading...</div>
}
// Once the user request finishes, show the user
return (
<div>
<h1>Your Account</h1>
<p>Username: { *** ON.stringify(user.username,null)}</p>
<p>Email: { *** ON.stringify(user.email,null)}</p>
<p>Address: { *** ON.stringify(user.address,null)}</p>
</div>
)
}
export default Profile
请注意,您需要在此构建某种加载 UI,以便在客户端提出加载后请求时保留空间。
如果想简化操作并在服务器端运行身份验证,可以将身份验证请求添加到 `getServerSideProps` 函数中,Next 会等待请求完成后再渲染页面。与上面代码段中的条件逻辑不同,你可以运行一些更简单的东西,比如 Next 文档中的简化版本:
import withSession from '../lib/session'
export const getServerSideProps = withSession(async function ({ req, res }) {
const { user } = req.session
if (!user) {
return {
redirect: {
destination: '/login',
permanent: false,
},
}
}
return {
props: { user },
}
})
const Profile = ({ user }) => {
// Show the user. No loading state is required
return (
<div>
<h1>Your Account</h1>
<p>Username: { *** ON.stringify(user.username,null)}</p>
<p>Email: { *** ON.stringify(user.email,null)}</p>
<p>Address: { *** ON.stringify(user.address,null)}</p>
</div>
)
}
export default Profile
这里仍然有处理身份验证失败的逻辑,但会重定向到登录,而不是呈现加载状态。
那么,哪种方案适合你的项目呢?首先要评估你对身份验证方案的速度有多大信心。如果您的请求完全不耗费时间,您可以在服务器端运行这些请求,并避免加载状态。如果你想优先立即呈现某些内容,然后等待请求,那就跳过 `getServerSideProps` 并在其他地方运行身份验证。
在使用 Next 时,这是不对每个页面一概要求身份验证的一个很好的理由。这样做更简单,但意味着你首先会错过 *** 框架的性能优势。
不久前,PHP 8.0大张旗鼓地发布了。它带来了许多新特性、性能增强和变化——其中最令人兴奋的是新的JIT编译器。 技术世界总是在向前发展,PHP也是如此。 ,包含了几个令人兴奋的特性。它定于今年晚些时候于2021年11月25日发布。 在本文中,我们将详细介绍PHP 8.1将带来哪些新的东...
宝塔面板现在已经成为国内许多站长必备的服务器管理必备工具。相比直接使用SSH+FTP来管理服务器,宝塔面板可以提供可视化管理,包括文件管理、数据库管理、数据备份、SSL配置等等。 如果你希望更简单高效地管理您的网站及服务器,宝塔面板是不错的选择。下面是一些宝塔面板安装及常见问题:...
本章节主要是对宝塔面板的主界面的各个版本进行一个简单的说明。 宝塔面板主界面主要包括:服务器操作系统、服务器状态、站点信息、软件管理及网络流量几个部分。 Windows面板有部分功能未实现,其余部分与Linux面板同步。 系统操作...
JavaScript是世界上最流行的编程语言之一。今天,它为数百万个网站提供支持,并吸引了成群的开发人员和设计人员为Web构建功能。如果您是编程新手,那么 JavaScript很容易成为之一。 在最初的20年里,JavaScript主要用于客户端脚本。由于JavaScript只能在<scr...
经过几个小时的努力工作后,您是否感到眼睛疲劳或难以阅读代码?许多程序员在开始头疼之前从没想过要切换字体。 如果您经常发现在尝试扫描一千行代码时眼睛模糊不清,或者在停止编码数小时后头疼,那么可能是时候尝试一种新字体了。即使您没有遇到这些症状,设计良好的字体通常也比默认系统字体具有更好的可读性。...
想成为一名网络开发人员或好奇工作的哪些子类型的薪水最高?Web开发是一个竞争激烈、多样化的行业,随着新语言和框架的出现而不断发展。 询问Web开发人员的薪水是一个难以解决的问题(尽管我们尝试)。有太多的因素需要考虑。 无论您是自由开发者还是有兴趣从事更传统的工作、喜欢前端或后端工作,或者想知...